Hello.
I’ve needed to implement proper handling of messages if TCP deceides to split them into 2 or more packets (so I’ve heard ). I did it and here’s the code, it reads short value in message header for message length and reads until it has full message, even if it is in multiple reads from channel. For this to work you’ll need to put message length at beggining as short value (2 bytes).
Only thing is I didn’t fully tested it yet, it’s good for normal transfers when message comes in one TCP packet but I can’t know if TCP split the packets while I was testing… and I’m too lazy to write a test case with custom length header and send the message 2 times
Any comments welcome.
// vars needed:
int bytes_read = 0; // Kova: bytes read from channel
boolean full_message_arrived = true; // Kova: is whole message transfered in received TCP packet
int bytes_left = 0; // Kova: when whole message didn't arrive, this much must be read to complete it on next channel read
int packet_size = 0; // Kova: header of message contains message size so it can be read properly if TCP dosen't send all data in one transfer
int read_times = 0; // Kova: for reading bytes from read buffer n times to message buffer
boolean keep_read_buffer_data = false; // Kova: if message header about message size is split, hold data until rest of header arrives and then process it
....
....
// before reading you usually clear the buffer, add condition to that
if (!keep_read_buffer_data)
read_buffer.clear();
....
....
while ((bytes_read = sc.read(read_buffer)) > 0) {
System.out.println("BYTES READ: " + bytes_read); :'(
read_buffer.flip();
while (read_buffer.hasRemaining()) {
if (full_message_arrived) { // Kova: Start reading new message from packet
if (read_buffer.remaining() == 1) {
keep_read_buffer_data = true;
byte save_me = read_buffer.get();
read_buffer.clear(); // Kova: gets rid of last, processed message
read_buffer.put(save_me); // ... but saves 1 byte that you need
break; // Kova: only 1 byte left, 1 more missing for short, wait for it in next packet
}
packet_size = read_buffer.getShort();
if (packet_size <= read_buffer.remaining()) { // Kova: whole message arrived in packet
read_times = packet_size;
bytes_left = 0; // Kova: mark full message arrived so it's get processed
} else {
full_message_arrived = false;
bytes_left = packet_size - read_buffer.remaining();
read_times = read_buffer.remaining();
}
message.clear();
for (int i=0; i < read_times; i++)
message.put(read_buffer.get());
} else { // Kova: reading last message wasn't complete, continue reading
read_times = (read_buffer.remaining() >= bytes_left)? bytes_left : read_buffer.remaining();
for (int i=0; i < read_times; i++) {
message.put(read_buffer.get());
bytes_left--;
}
}
if (bytes_left == 0) { // Kova: full message here, process it
full_message_arrived = true;
message.flip();
processClientMessage(message, sc);
}
}
} // end: while loop for reading from channel
EDIT: blahblahblahh was so nice and took a look at the code, he discovered a bug, details below, I edited this code, bug is fixed.