0

I'm using winsock in my application to mantain client-server connection, and using non-blocking sockets in order to do that. But sometimes when I get FD_READ message, it appears that recv() returns not one, but two packets.

I tried to change sizes of packets so they differ from each other and then compared it with amount of data recv() is returning. I'm 100% sure I receive two packets from time to time. I think my ping function is to be blamed. I have a thread in my app that sends ping message from time to time. Then the other side replies with another message. Not sure if that's the best way to do that but whatever, it doesn't matter right now.

What I know for sure is sometimes these messages get "mixed", so recv() returns "ping request" and "ping answer" at once. How does it happen? Isn't recv() supposed to return just the amount of data that single send() call sent? Even if sometimes client or server gets "ping request" message and replies to it, while sending its own "ping request" message, even if such unfortunate timing is possible, shouldn't other side be able to differ one packet from another and return one per FD_READ message?

DuncanACoulter
  • 2,095
  • 2
  • 25
  • 38
PookyFan
  • 785
  • 1
  • 8
  • 23

2 Answers2

1

It's likely the case then that you have indeed received two packets between the last time you called recv and the time you get two packets. recv isn't going to get one packet at a time, it'll read in all the data available in the buffer. This means there might be more than a single data message available or there might be only part of a message available. (If it's a large enough message, it'll be split into multiple packets.) It's your job to decode your own data. A simple way to do this is by adding a header with some information to help you, like a message ID or an indication of the expected data size. Generally a footer with a CRC to verify the data integrity (and ensure you have a complete message) doesn't hurt either.

Anthony
  • 2,256
  • 2
  • 20
  • 36
1

TCP is a stream of data, not a stream of packets. UDP is a stream of packets. As Anthony said, if you're using TCP, you have to handle where one section of data ends and the next begins.

mark
  • 5,269
  • 2
  • 21
  • 34
  • So if I used UDP I wouldn't get this problem? – PookyFan May 21 '13 at 20:09
  • OK I get it. One more thing: when I get this double-packet crap from recv(), do I get one or two FD_READ messages? I mean - when I get FD_READ and call recv() getting both packets to my buffer, does my app send another FD_READ message? – PookyFan May 21 '13 at 20:17
  • Scratch my earlier comment. UDP would be easier for you to use because, as mark mentioned, it does honor packet boundaries (one read will yield one packet). That might be easier for you to use but you'll still need a way to distinguish between packets (size might not always work). – Anthony May 21 '13 at 20:24
  • Think of it more like this: if there's data available, the socket will be signaled and recv will succeed with something. Let's say you decided to send string lines as your messages, terminated by CR-LF (\r\n). You might have a partial line, you might have a complete line, you might have a line and a half, or you might have more. Although you may have full messages frequently, you can't guarantee it. You can easily solve the problem by buffering partial messages until you have a complete message; i.e. if you don't have a CR-LF in this example, then you don't have a complete message yet. – mark May 21 '13 at 20:24