Advertisement

Server call to non-blocking send succeds but client don't receive packet

Started by April 18, 2017 09:01 PM
12 comments, last by hplus0603 7 years, 7 months ago

"IF send() returns me the right number (the total size of the packet), then the packet WILL arrive at destination (unless catastrophic events of course) and it will arrive before anything other that I send after this send, is that right?" If send returns the right number, the data is sent. It will either eventually arrive, or the connection will get dropped.

"After successfully sending the critical message, the server calls shutdown" - You might want to look up the setSockOpt function and the SO_LINGER value.

Alternatively - and probably preferable - wait for the client to confirm that it has connected to the new server before kicking it off the old one. That way you can be sure that the information has got through.

"IF send() returns me the right number (the total size of the packet), then the packet WILL arrive at destination (unless catastrophic events of course) and it will arrive before anything other that I send after this send, is that right?" If send returns the right number, the data is sent. It will either eventually arrive, or the connection will get dropped.

"After successfully sending the critical message, the server calls shutdown" - You might want to look up the setSockOpt function and the SO_LINGER value.

Alternatively - and probably preferable - wait for the client to confirm that it has connected to the new server before kicking it off the old one. That way you can be sure that the information has got through.

I found this digging the web...

https://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable

It's true? should I wait for recv to return 0 instead of setting SO_LINGER?

The final process will then be:

-server calls shutdown on writing side

-So, the client reads until the recv call return 0 (that will happen only after the server calls shutdown right?)

-then, it just closesocket.

-the server's call to recv will now return 0, and it can now safetely call closesocket.

Advertisement

"should I wait for recv to return 0 instead of setting SO_LINGER?" - No. Keep reading:

"Using the shutdown() technique above really only tells us that the remote closed the connection. It does not actually guarantee that all data was received correctly by program B. [..] The best advice is [..] to have the remote program actively acknowledge that all data was received."

That's why I said you should probably wait for the client to confirm that it has connected to the new server.

I take a different approach to closing. Once I know that I've received all the data I need, and I don't have anything I need to send to the server anymore, I just close() the connection on the client side.
On the server side, I will time out a client if I haven't received any data for X seconds, but I will also time out the client if i get an error trying to send() or recv() to/from the client (this means the kernel got the message that my client has closed the connection.)
Lingering/waiting just doesn't buy you anything in these cases. When the server tells you "you need to be talking to this other server," you already know that no more commands to the original server matter, and you shouldn't need any more data from that original server, either.

Separately, how do you detect that you "don't get the data" ?
Specifically, TCP will mush packets together, and also break them apart, so that a single call to send() on a server may end up being received as one, two, three, or more calls to recv() on the client, depending on network conditions.
Thus, if you assume that a single call to send() on the server will correspond to a single call to recv() on the client, you will lose data, and see data that's in the middle of a packet, and such.
Thus, every packet on top of a TCP connection must be preceded by a fixed-length "length" field. For games, you'll seldom want more than a few kilobytes per packet, so a two-byte 16-bit length field should be plenty.
Then, the receiving end can receive until they have at least two bytes (note: you may receive only one in the first call to recv()!) and once it has two or more bytes, check whether it has enough bytes to decode a full packet. If so, decode and remove the packet from the buffer, else keep reading until you have a full packet in the buffer.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement