部分接收来自套接字C ++的数据包 [英] Partial receipt of packets from socket C++

查看:93
本文介绍了部分接收来自套接字C ++的数据包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了麻烦,我的服务器应用程序发送了8字节长的数据包-AABBCC1122334455,但是我的应用程序通过"recv"功能分为两个部分AABBCC1122334455接收了此数据包,我该如何解决? /p>

谢谢!

解决方案

总结一点点:

  1. TCP连接无法在应用程序级别上处理数据包或消息,您正在处理字节流.从这个角度来看,这类似于从文件写入和读取.
  2. sendrecv都可以发送和接收的数据少于参数中提供的数据.您必须正确处理它(通常通过在调用周围应用适当的循环).
  3. 在处理流时,必须找到在应用程序中将其转换为有意义的数据的方法.换句话说,您必须设计序列化协议.

根据您已经提到的内容,您很可能希望发送某种消息(嗯,通常是人们所做的事情).关键是要正确发现消息的边界.如果您的消息是固定大小的,则只需从流中获取相同数量的数据并将其转换为您的消息即可;否则,您需要使用其他方法:

  • 如果您想出一个消息中不存在的字符,则它可能是您的定界符.然后,您可以阅读流,直到到达角色为止,这将成为您的信息.如果您传输ASCII字符(字符串),则可以使用零作为分隔符.

  • 如果您传输二进制数据(原始整数等),则所有字符都可以出现在消息中,因此没有任何字符可以用作分隔符.在这种情况下,最常见的方法可能是使用包含邮件大小的固定大小前缀.此额外字段的大小取决于消息的最大大小(使用4个字节可能会很安全,但如果知道最大大小是多少,则可以使用较小的值).然后,您的数据包将看起来像SSSS|PPPPPPPPP...(字节流),其中S是附加大小字段,而P是您的有效负载(应用程序中的实际消息,P字节数由的值确定). S).您知道每个数据包都以4个特殊字节(S字节)开头,因此您可以将它们读取为32位整数.一旦知道封装的消息的大小,就可以读取所有P字节.处理完一个数据包后,就可以从套接字读取另一个数据包了.

好消息是,您可以提出完全不同的建议.您只需要了解如何从字节流中反序列化消息以及send/recv的行为方式.祝你好运!

将任意数量的字节接收到数组中的函数示例:

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;
}

接收带有2字节前缀定义有效负载大小的数据包的示例(然后将有效负载的大小限制为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
}

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!

解决方案

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
}

这篇关于部分接收来自套接字C ++的数据包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆