Java Server Socket with Client in C - java

I have written the server socket code in java. The relevant lines are:
byte[] bRecieved = new byte[440] ;
1int i =in.read(bRecieved);
Arrays.toString(bRecieved);
This works fine if the client is written in java
byte[] bSend = {1,2,3,4};
DataOutputStream out =
new DataOutputStream(outToServer);
out.write(bSend);
But the Client is written in C++. The code for sending is:
if (client.connect(serverIP, serverPort)) {
String msg="Hello Server";//Message to be sent
client.println(msg);//send the message
}
My question is , how do I communicate with the java server wanting bytes? The connection is successful and bytes are printed on the server console. But they are not "Hello Server". Do I have to iterate through the bytes and interpret them as chars? Chars and int are 1 byte in c++.
Please clarify this situation if possible.
Thanks in advance!

What library are you using for your C++ sockets?
You might try flushing the stream?

The C++ client is line-buffered by default. This means it won't actually send the data until either a newline is pushed onto the outbound data or the buffer holding data to be sent fills beyond a certain point (system dependent). If you want to see this in action set your msg string to "Hello Server\n". Your data should be sent right away.
The flush() command says, "send all data now, regardless of how much is in the buffer." So you can choose to do one other the other, either call flush() or append a newline. Of course if you use the newline, the Java process will receive a newline character in addition to the string, which may or may not be what you want. Generally, when performing network operations, you want to call flush() whenever you're done adding things to the outbound buffer.

Related

Open more than one stream between socket and serversocket

I'm creating a simple chat in Java, and it works. I just have a problem when a client close the connection, because it continue to appear online. This is because there's no a way to know when a stream is closed.
I searched on google and any solution has not resolved my problem, so I want to send a boolean each 300ms and, if I don't receive any answer or I get an error, I can close the connection server side.
The problem is that there's a conflict in the stream, I can't know if I'm reading a boolean or a text, so sometimes my CheckConnection class try to read a string and my SocketHandler class try to read a boolean, and I receive an error.
I use the class ObjectInputStream and ObjectOutputStream to read and write into the stream.
It's my first server application and I don't know very much about it, I don't know if it's possible open more than one stream or if there are other solutions, so I'm asking you. What may I do?
PS: I tried to create a PrintStream and execute the checkError() method, but it returns always false, even if I close explicitly all the streams client side. Thank you.
I suggest you use text as this is simpler to work with to start with.
treat any message as a heartbeat. If you get data, the connection is still good.
treat a heartbeat as a string and chat as a string. it's all a String so you don't need to worry about what it is.
check a stream is open by attempting to read from it and expecting you will get something within a timeout period.
You can use BufferedReader, or Scanner to reads the text. You can user BufferedWriter to write the text.
In your string you can create a simpler protocol like this.
say [to-whom] [message ...]
for the heartbeat you can have
hb
or
heartbeat
or
say nobody hi
You might add commands like
login [user] [password]
and
kthxbye
To decode the message, look at the first word and you know it's purpose and then read the second word for say and the rest of the string is the message.
To test the protocol, you can telnet to the port and type in stuff to the server directly. You don't even need to write a client to start with.

Entering data into an InputStream

I know that InputStreams are for reading, and OutputStreams are for writing... but if I have an application that passes all data from an InputStream to the remote side and pushes all received data from that remote side to the OutputStream and I need to send dynamic data to that remote side... how would I enter it into the InputStream? I can do this easily in the Java console since anything entered in is put into System.in and sent to that remote side, and anything coming back is processed through System.out, but obviously I cannot use a Java console in production. How would I emulate this functionality e.g. create a button that sends "command X\r" as if it were typed into the java console?
Note: For background, I'm using JSch to SSH into a Cisco ASA. Where I have set Channel.setInputStream(System.in) and Channel.setOutputStream(System.out) to communicate through console successfully.
I am not familiar with JSch, and I suspect you have this backwards. First, according to their example, you should actually be executing commands with Channel.setCommand(). Then you can use Channel.getInputStream() to obtain a stream that you can read the remote response from.
That aside, a cursory glance at the documentation seems to suggest that you should use the channel's existing streams and read to / write from them, e.g.:
OutputStream out = Channel.getOutputStream();
String str = "command X\r";
out.write(str.getBytes("us-ascii"));
This would make more sense and is much easier to deal with on your end.
However, as to the general question regarding InputStreams: You can use any InputStream as a source for data. It just so happens that System.in is one that comes from standard input (which is essentially a file).
If you want to use data constructed on the fly, you could use a ByteArrayInputStream, e.g.:
String str = "command X\r";
InputStream in = new ByteArrayInputStream(str.getBytes("us-ascii"));
// do stuff with in
You can use any character encoding you want if us-ascii is not appropriate.
But, again, I suspect you are doing this slightly backwards.

Unknown AMF type & other errors when transfering files from flash to java

I'm using a Flash tool to transfer data to Java. I'm having problems when it comes to sending multiple objects at once. The objects being sent are just generic Object objects, so it's not a case of needed to register a class alias or anything.
Sending one object works fine. Once I start sending multiple objects (putting the same Objects in an Array and sending that), it starts getting weird. Up to three objects in an Array seems to work fine. More than that I get different errors in the readObject() function, such as:
Unknown AMF type '47'
Unknown AMF type '40'
Unknown AMF type '20'
OutOfBoundsExceptions index 23, size 0
NullPointerException
etc.
Sending 3 objects will work, sending 4 gives me the error. If I delete one of the previous 3 that worked (while keeping the fourth that was added), it'll work again. Anyone know what's going on?
Some more info:
Communication goes through a Socket class on the Flash side. This is pure AS3, no flex.
Messages are compressed before being sent and decompressed on the server, so I'm pretty sure it's not a buffer size issue (unless I'm missing something)
BlazeDS version seems to be 4.0.0.14931 on the jar
Flash version is 10.1 (it's an AIR app)
Update with rough code
Examples of the objects being sent:
var o:Object = { };
o._key = this._key.toString();
o.someParam = someString;
o.someParam2 = someInt;
o.someParam3 = [someString1, someString2, someString3];
...
It's added to our event object (which we use to determine the event to call, the data etc to pass). The event object is been registered as a class alias
That object is sent to the server through a Socket like so:
myByteArray.writeObject( eventObj );
myByteArray.compress();
mySocket.writeBytes( myByteArray );
mySocket.flush();
On the server side, we receive the bytes, and decompress them. We create a Amf3Input object and set the input stream, then read it:
Amf3Input amf3Input = new Amf3Input( mySerializationContext );
amf3Input.setInputStream( new ByteArrayInputStream( buffer ) ); // buffer is a byte[]
MyEventObj eventObj = (MyEventObj)amf3Input.readObject(); // MyEventObj is the server version of the client event object
If it's going to crash with an "unknown AMF type error", it does so immediately i.e. when we try to read the object, and not when it's trying to read a subobject.
In stepping through the read code, it seems when I pass an array of objects, if the length is <= 4, it reads the length right. If the length is bigger than that, it reads it's length as 4.
If you're getting AMF deserialization errors, there are several possible issues that could be contributing to the problem. Here are several techniques for doing further diagnostics:
Use a network traffic sniffer to make sure that what you are sending matches what you are receiving. On the Mac I'll use CocoaPacketAnalyzer, or you can try Charles, which can actually decode AMF packets that it notices.
Feed the data to a different AMF library, like PyAMF or RocketAMF to see if it's a problem with BlazeDS or with how you're calling it. It's also possible that you may get a different error message that will give you a better idea of where it's failing.
Check the format of the AMF packet. AMF server calls have some additional wrapping around them that would throw off a deserializer if it's not expecting to encounter that wrapping, and vice versa for purely serialized objects. Server call packets always start off with a 0x00, followed by the AMF version (0x00, 0x03, or in rare cases 0x02).
Ok, I figured out the problem. Basically messages are compressed before being sent and decompressed on the server. What I didn't see was that the byte[] buffer that the message was being decompressed to was always 1024 length, which was fine for small arrays of objects. Once that was passed however, it would overwrite the buffer (I'm not quite sure what happens in Java when you try to write more bytes than are available - whether it loops back around, or shifts the data).
When it came to reading the amf object, the first thing it does it read an int, and uses this to determine what type of object it's trying to decode. As this int was gibberish (47, 110, -10), it was failing.
Time to start prepending message lengths I think :)
Thanks for the help.

Problem with C server socket connected to Java client

I am writing an application on Android, and I want it to be able to know when the server (which I have written in C) dies or is shutdown. I am trying to implement this by having the server send a message to the client (the Android app) at a specified interval. If this message doesn't come, then the client knows that it is no longer connected to the server. They communicate using TCP sockets.
My problem is that the Android app cannot seem to read what the server writes. When it gets to the first part of the code where it tries to read from the server socket, it just hangs. In the Android app I am using a BufferedReader to read from the socket tmpstr = inFromServer.readLine(); where tmpstr is a string and inFromServer is the BufferedReader, and the C server is just using write write(newsockfd,"I got your message",18);.
I also tried using an alternative java server to see if my basic program logic was wrong. The test server used a PrintWriter, and it worked perfectly with the Android client.
What am I missing here? Is there a difference in the way Java and C buffer (or don't buffer) their data? If I need to give any additional information, please let me know.
Edit: I also have no trouble getting the C server to read data sent from the client. I only have trouble with getting the client to read data that is sent from the server.
Edit: The problem was fixed by adding a newline character (\n) to what the server sends to the client.
If I recall correctly, readLine() is not going to return the result until it has read a full line. It is going to block until then. You are not sending a full line from the C program.
Not only are you not sending a full line (\n terminated), but you also aren't even sending your entire C string since you're not sending the null terminator (Your C string actually contains 19 characters, not 18, if you include the null terminator). I don't recall what type of string format Java uses, if it's null terminated or not, but that part probably doesn't matter since it's looking for a \n, not a \0.
Try sending "I got your message\n" from the C server and let us know what happens then.
Oops, I just realized that the question had already been answered in the comments to it. Oh well. People really should post answers as answers.

Java Socket program can not read data if the server sends data using write and recieves data using readUTF()

I have written a socket program where the client uses readUTF() and writeUTF() to communicate with the server while the server uses read() and write() to communicate with client.
My server can read all the data coming from server. I am using write() on the server side and readUTF() in client side.
So, in this scenario my client is unable to get all the data that is sent by the server if the data size is large, only some portion of data is received.
What should be done to ensure that all data is transmitted?
Do not use readUTF and writeUTF in this scenario. Instead read and write byte arrays:
read(byte [] b)
Then convert the byte array to a String using the appropriate String constructor:
public String(byte[] bytes,
String charsetName)
You should try-catch UnsupportedEncodingException exceptions.
Note that readUTF and writeUTF use a modified form of UTF. I don't know what you're sending using read() and write() on the server, but you should ensure that there's compatibility between what the client expects and what the server expects.
I would make both client and server send/receive using the same method. I don't know if that's causing your problem, but it will save you some unrelated grief.

Categories