从套接字C ++部分接收数据包

时间:2012-05-25 17:03:00

标签: c++ sockets network-programming packet

我遇到了麻烦,我的服务器应用程序发送长度为8个字节的数据包 - AABBCC1122334455但是我的应用程序通过“recv”函数分两部分AABBCC1122334455接收此数据包我能解决这个问题吗?

谢谢!

4 个答案:

答案 0 :(得分:5)

总结一下liitle:

  1. TCP连接不适用于应用程序级别的数据包或消息,您正在处理字节流。从这个角度来看,它类似于从文件中写入和读取。
  2. sendrecv都可以发送和接收的数据少于参数中提供的数据。你必须正确处理它(通常通过在呼叫周围应用适当的循环)。
  3. 当您处理流时,您必须找到将其转换为应用程序中有意义数据的方法。换句话说,您必须设计序列化协议
  4. 从你已经提到的内容来看,你很可能想要发送某种消息(好吧,这通常是人们所做的)。关键是要正确发现消息的边界。如果您的邮件大小固定,您只需从流中获取相同数量的数据并将其转换为您的邮件;否则,你需要一个不同的方法:

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

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

    好消息,你可以想出一些完全不同的东西。您需要知道的是如何从字节流中反序列化您的消息以及P / send的行为方式。祝你好运!

    修改

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

    recv

    接收带有2字节前缀的数据包的示例,定义了有效载荷的大小(有效载荷的大小限制为65kB):

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

通过从循环 中的TCP套接字 读取“修复”,直到您获得足够的字节来理解您的应用程序。

答案 3 :(得分: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);