1

我遇到了麻烦,我的服务器应用程序发送了 8 字节长度的数据包 -AABBCC1122334455但我的应用程序分两部分接收此数据包,AABBCC1122并且334455通过“recv”功能,我该如何解决?

谢谢!

4

4 回答 4

7

总结一点:

  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
}
于 2012-05-25T17:55:39.073 回答
1

这就是recv()在大多数平台上的工作方式。您必须检查收到的字节数并继续循环调用它,直到获得所需的数字。

于 2012-05-25T17:06:17.340 回答
1

您可以通过在循环中从 TCP 套接字读取来“修复”该问题,直到您获得足够的字节以对您的应用程序有意义。

于 2012-05-25T17:09:28.703 回答
0

我的服务器应用程序发送 8 字节长度的数据包

并不真地。您的服务器发送 8 个单独的字节,而不是 8 个字节长的数据包。TCP 数据通过字节流而不是数据包流发送。TCP 既不尊重也不维护您可能想到的任何“数据包”边界。

如果您知道您的数据是以 N 字节的数量提供的,则recv在循环中调用:

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

如果您的数据包是可变长度的,请尝试在数据本身之前发送它:

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); 
于 2012-05-25T17:10:05.360 回答