Partial receipt of packets from socket C++

*爱你&永不变心* 提交于 2019-12-10 11:48:55

问题


I have a trouble, my server application sends packet 8 bytes length - AABBCC1122334455 but my application receives this packet in two parts AABBCC1122 and 334455, via "recv" function, how can i fix that?

Thanks!


回答1:


To sum up a liitle bit:

  1. TCP connection doesn't operate with packets or messages on the application level, you're dealing with stream of bytes. From this point of view it's similar to writing and reading from a file.
  2. Both send and recv can send and receive less data than provided in the argument. You have to deal with it correctly (usually by applying proper loop around the call).
  3. As you're dealing with streams, you have to find the way to convert it to meaningful data in your application. In other words, you have to design serialisation protocol.

From what you've already mentioned, you most probably want to send some kind of messages (well, it's usually what people do). The key thing is to discover the boundaries of messages properly. If your messages are of fixed size, you simply grab the same amount of data from the stream and translate it to your message; otherwise, you need a different approach:

  • If you can come up with a character which cannot exist in your message, it could be your delimiter. You can then read the stream until you reach the character and it'll be your message. If you transfer ASCII characters (strings) you can use zero as a separator.

  • If you transfer binary data (raw integers etc.), all characters can appear in your message, so nothing can act as a delimiter. Probably the most common approach in this case is to use fixed-size prefix containing size of your message. Size of this extra field depends on the max size of your message (you will be probably safe with 4 bytes, but if you know what is the maximum size, you can use lower values). Then your packet would look like SSSS|PPPPPPPPP... (stream of bytes), where S is the additional size field and P is your payload (the real message in your application, number of P bytes is determined by value of S). You know every packet starts with 4 special bytes (S bytes), so you can read them as an 32-bit integer. Once you know the size of the encapsulated message, you read all the P bytes. After you're done with one packet, you're ready to read another one from the socket.

Good news though, you can come up with something completely different. All you need to know is how to deserialise your message from a stream of bytes and how send/recv behave. Good luck!

EDIT:

Example of function receiving arbitrary number of bytes into array:

bool recv_full(int sock, char *buffer, size_t size)
{
  size_t received = 0;
  while (received < size)
  {
    ssize_t r = recv(sock, buffer + received, size - received, 0);
    if (r <= 0) break;
    received += r;
  }

  return received == size;
}

And example of receiving packet with 2-byte prefix defining size of payload (size of payload is then limited to 65kB):

uint16_t msgSize = 0;
char msg[0xffff];

if (recv_full(sock, reinterpret_cast<char *>(&msgSize), sizeof(msgSize)) &&
    recv_full(sock, msg, msgSize))
{
  // Got the message in msg array
}
else
{
  // Something bad happened to the connection
}



回答2:


That's just how recv() works on most platforms. You have to check the number of bytes you receive and continue calling it in a loop until you get the number that you need.




回答3:


You "fix" that by reading from TCP socket in a loop until you get enough bytes to make sense to your application.




回答4:


my server application sends packet 8 bytes length

Not really. Your server sends 8 individual bytes, not a packet 8 bytes long. TCP data is sent over a byte stream, not a packet stream. TCP neither respects nor maintains any "packet" boundary that you might have in mind.

If you know that your data is provided in quanta of N bytes, then call recv in a loop:

std::vector<char> read_packet(int N) {
  std::vector buffer(N); 
  int total = 0, count;
  while ( total < N && (count = recv(sock_fd, &buffer[N], N-total, 0)) > 0 )
    total  += count;
  return buffer;
}

    std::vector<char> packet = read_packet(8);

If your packet is variable length, try sending it before the data itself:

int read_int() {
  std::vector<char> buffer = read_packet(sizeof (int));
  int result;
  memcpy((void*)&result, (void*)&buffer[0], sizeof(int));
  return result;
}

  int length = read_int();
  std::vector<char> data = read_buffer(length); 


来源:https://stackoverflow.com/questions/10758547/partial-receipt-of-packets-from-socket-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!