• Create Account

Need scary sound effects or creepy audio loops for your next horror-themed game? Check out Highscore Vol.3 - The Horror Edition in our marketplace. 50 sounds and 10 loops for only \$9.99!

### #Actualhplus0603

Posted 29 May 2012 - 12:21 PM

First: This is actually answered in the FAQ.

Second: You should not block on TCP receive until a full packet is received. Doing so means that your loop will be frozen if someone sends a half packet. This could be because of a crash, or because of sudden network disconnection, or because of a malicious user, or whatever.

In general, you want the network step of your main loop to be:

- If the socket has data, drain the TCP socket. Typically, this means calling recv() into some cyclic buffer with a big "ask" -- recv() will only return what's actually there.
- Look at the head of your drain buffer. If there is enough data there to tell what the packet header is, look at the packet header. If there is enough data there to cover the entire packet length as shown by the header, dequeue that packet and move the drain buffer read pointer forward by as much. Handle the packet, and repeat this step.

Specifically, you want to "drain" the network quickly, and then use pointer arithmetic and byte inspection to sort out whatever data you have. This is more efficient, more robust, and easier to implement than code that tries to only call recv() for the header / data parts. Consider if you have a length field of more than one byte, and you only recv() half of that field -- now what?
If the packet structure is <id-as-uint16, length-as-uint16, payload> then the decode when you read to a given buffer is simple:

  if (buffer.available() >= 4) { // have a header
uint16 len = (buffer[2] << 8) | buffer[3]; // assume buffer is unsigned char
if (buffer.available() >= 4 + len) { // have all the payload
uint16 type = (buffer[0] << 8) | buffer[1];
handle_packet(type, len, &buffer[4]); // or whatever
buffer.remove_front(4 + len);
}
}


### #1hplus0603

Posted 29 May 2012 - 12:20 PM

First: This is actually answered in the FAQ.

Second: You should not block on TCP receive until a full packet is received. Doing so means that your loop will be frozen if someone sends a half packet. This could be because of a crash, or because of sudden network disconnection, or because of a malicious user, or whatever.

In general, you want the network step of your main loop to be:

- If the socket has data, drain the TCP socket. Typically, this means calling recv() into some cyclic buffer with a big "ask" -- recv() will only return what's actually there.
- Look at the head of your drain buffer. If there is enough data there to tell what the packet header is, look at the packet header. If there is enough data there to cover the entire packet length as shown by the header, dequeue that packet and move the drain buffer read pointer forward by as much. Handle the packet, and repeat this step.

Specifically, you want to "drain" the network quickly, and then use pointer arithmetic and byte inspection to sort out whatever data you have. This is more efficient, more robust, and easier to implement than code that tries to only call recv() for the header / data parts. Consider if you have a length field of more than one byte, and you only recv() half of that field -- now what?
If the packet structure is <id-as-uint16, length-as-uint16, payload> then the decode when you read to a given buffer is simple:

  if (buffer.available() >= 4) { // have a header
uint16 len = (buffer[2] << 8) | buffer[3]; // assume buffer is unsigned char
if (buffer.available() >= 4 + len) { // have all the payload
handle_packet(buffer, 4, len); // or whatever
buffer.remove_front(4 + len);
}
}


PARTNERS