marking end of packet with null in ByteBuffer

Hello once more.
I wanted to put in marking at the end of my packet with null (I heard is popular) in case TCP dosen’t send everything in one go. I can’t ByteBuffer.put(null), so how it is done? One more thing, if TCP does split data in more then one send, what is the smallest type based on split? Is it byte or something else? I’m wondering couse I read data from buffer with getInt() and getFloat(), so if message is split so int value is 3 bytes in first message, and 1 remaining in next one, with getInt() in first message I’ll couse buffer overflow.
Thank you.

Since this is a TCP stream, none of this is needed at all. TCP is a guaranteed stream. Meaning if you send a ByteBuffer with 1024 bytes of integer values (just as an example) then the other end will receive exactly the same amount of bytes in the exact order they we’re sent. Also TCP packets have a guaranteed arrival too. Meaning if a packet get losts or dropped, the TCP stream will attempt to resend it until it gets sent. Oh and it’s not possible to write a null value to a ByteBuffer anyway.

He meant split packets… well… just set the appropriate position/limit and wait for the ByteBuffer to have no remaining bytes, if you don’t care that much about performance :slight_smile:

Null terminating packets within a stream (which is somewhat more work than just doing ByteBuffer.put(0x0)) sounds like a way of introducing all sorts of really annoying and awkward bugs - at step backwards to the days of null-terminated strings really.

I generally find it better to have the message length (in bytes) as the first element of all messages, this means that even if the message body is screwed up you can just drop the thing and carry on. If you’re really tight on bandwidth then you can make the length optional based on the message type (ie. your message header is [messageType][optional length][data] ).

And encode the length-value so that it can be 1 or 2 bytes wide (depending on the sign-bit, for example)

And if you’re in that situation it might be better to put a few game-packets into a single TCP-packet.

Well, null terminated marker byte is widely used method to separate different packets. If clients write multiple packets and replys are sent asynchronously then client MUST KNOW when splitting an incoming bytes to separate reply packets. Socket is like a tube where other end throws bytes into, and receiving end reads continous flow.

Read incoming bytes until you get 0x00 byte. Then split leftside bytes as a completed message. Rightside bytes goes to the next message until null byte is read again.

Splitting application packet must be tell somehow, and null byte is widely used for string based messages. Another method is writing a lenOfData value.

I have written null byte to SocketChannel without problems. It is not null value, but 0x00 byte value. Big difference. I always use UTF-8 string bytes and works fine.
byte[] bytes = myMessage.getBytes(“UTF-8”);

Using terminator marker is more fail tolerance than lenOfData value at the start of message. Imagine if broken client writes the following [lenOfData][data] data: “5abcdefgh”

You read a length of 5 and then next five bytes. 6th value should indicate length of next packet but…

And using a terminator marker you can stream data to sockets without precalculate the length. This is a big saving for larger packets as you can start writing it immediately.

tnx guys, that was very helpfull
so it’s .put(0x0) then. I’m wondering, what is this value? Hex 0? All bits 0? So it’s like -2^8 / 2 = -128 if it’s read like byte number?
Nobody still anwsered how TCP could split data… should I always use .get() and put pieces together manually or can I use bigger fragments like .getInt() and not to be afraid of buffer overflow.

Riven, your suggestion about sending multiple identical packets at once is sloppy, I’m pretty much sure this is not way to go even if you have small game like me (where a packet is less then 200 bytes). I probably don’t even need to worry about TCP spliting my messages, but I want to learn how to do stuff correctly.

Here is a code snippet to give some ideas. I cannot give you a full working example until I have ask my managers to give my code away.

See how you can reuse terminator bytebuffer and how you dont need to merge two byte arrays together. SocketChannel has a write method where you give an array of ByteBuffer instances. It will write bytes from all buffers.


public class ClientConnection {
  private static final byte[] TERMINATOR_BYTEARRAY = new byte[] { (byte)0x00 } ;
  private ByteBuffer[] curOutBuffers;
  ...
Constructor:
  // curOutBuffers[0] = current outgoing bytes is given later in a code
  // curOutBuffers[1] = reuse same terminator bytebuffer instance
  curOutBuffers = new ByteBuffer[2];
  curOutBuffers[1] = ByteBuffer.wrap(TERMINATOR_BYTEARRAY);
  ...
Write method:
  here you must handle FIFO queue, put 2nd packet to a queue until current
  one is fully written to a remote client.
  ...
  // this return stringToUTF8 bytes, and rewind terminator 
  // ByteBuffer before start writing
  curOutBuffers[0] = ByteBuffer.wrap(outPacket.getBytes()); 
  curOutBuffers[1].rewind();
  sc.write(curOutBuffers);
  if (hasRemaining()) {
     ... register OP_WRITE for this socketchannel
     ... and then write remaining bytes in a selector thread
  }
  ...

HasRemaining:
  // is all bytes written from current outPacket buffer.
  return (curOutBuffers[0].hasRemaining() ||
               curOutBuffers[1].hasRemaining());