Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading and writing data between c# and java sockets

I've been fighting with this all day. I need to send Strings (JSON) between a C# server and a Java client. I have to have the first 4 bytes (always 4 bytes) as the length of the message (the header so we know how long the rest of the message is) and then the body of the message. The streams stay open for the duration of the app's life. Personally I would have just delimited each message with a '\n' and then used readLine()'s but the client NEEDS it this way.

I need the C# side to send and receive these messages as well as the Java side. Not too sure how to encode and decode everything.

Some of the bits I've been playing with:

C# send

byte[] body = Encoding.ASCII.GetBytes(message);
byte[] header = BitConverter.GetBytes((long) body.Length);

foreach (byte t in header)
{
    networkStream.WriteByte(t);
}


foreach (byte t in body)
{
    networkStream.WriteByte(t);
}

I didn't get to C# receive yet. Java send:

byte[] dataToSend = data.getBytes();
byte[] header = ByteBuffer.allocate(4).putInt(dataToSend.length).array();
ByteArrayOutputStream output = new ByteArrayOutputStream();
output.write(header);
output.write(dataToSend);
output.writeTo(outputStream);

Java receive:

byte[] header = new byte[4];
int bytesRead;
do {
    Debug.log("TCPClient- waiting for header...");
    bytesRead = reader.read(header);

    ByteBuffer bb = ByteBuffer.wrap(header);
    int messageLength = bb.getInt();

    Debug.log("TCPClient- header read. message length (" + messageLength + ")");

    byte[] body = new byte[messageLength];
    do {
       bytesRead = reader.read(body);
    }
    while (reader.available() > 0 && bytesRead != -1);
}
while (reader.available() > 0 && bytesRead != -1);

I know the code is not all complete, but can anyone provide any assistance?

like image 366
Dylan Avatar asked Aug 15 '26 20:08

Dylan


1 Answers

Delimiting messages with '\n' is not a good idea, unless you’re sure that your messages will only consist of single-line text. If a '\n' occurs innately within one of your messages, then that message would get split up.

You state that the message length must be exactly 4 bytes; however, the following line generates an 8-byte array:

byte[] header = BitConverter.GetBytes((long) body.Length);

The reason is that, in C#, long is an alias for the Int64 struct, representing a 64-bit signed integer. What you need is an int or a uint, which represents a 32-bit signed or unsigned integer. Thus, just change the above line to:

byte[] header = BitConverter.GetBytes(body.Length);

Another important consideration you need to make is the endianness of your data. Imagine you’re trying to create a 4-byte array for a value of, say, 7. On a big-endian platform, this would get encoded as 0,0,0,7; on a little-endian platform, it would get encoded as 7,0,0,0. However, if it gets decoded on a platform having the reverse endianness, the 7 would be interpreted as the most significant byte, giving a value of 117,440,512 (equal to 7×2563) rather than 7.

Thus, the endianness must be the same for both your Java and your C# applications. The Java ByteBuffer is big-endian by default; however, the C# BitConverter is architecture-dependant, and may be checked through its IsLittleEndian static property. You can get C# to always follow the big-endian convention by reversing your array when it is little-endian:

byte[] header = BitConverter.GetBytes(body.Length);
if (BitConverter.IsLittleEndian)
    Array.Reverse(header);
like image 52
Douglas Avatar answered Aug 17 '26 08:08

Douglas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!