当只发送一条消息时从接收中获取两条消息

Getting two messages from receive when only one is sent

我编写了一个服务器,在打开与它的连接后应该等待来自客户端的消息:

while(1){
  if(recv(mySocket, buffer, 1000, 0) < 1){
     continue;
  }   
  printf("Message received: %s", buffer);
}

我用 wireshark 检查了哪些数据包被发送到这个服务器,但是对于每个发送的数据包,都有 2 个 printf 输出。

我现在的问题是我从哪里得到这条额外的消息。

(附加消息是一些随机字节。但每次都一样。)

您对 recv() 行为的明显期望是不合理的。正如@KarolyHorvath 在评论中观察到的那样,流式套接字(其中包括基于 TCP 的套接字)对 "messages" 没有任何意义。特别是,网络数据包不对应于流套接字上的消息。 POSIX 对 recv() 的行为有这样的说法,事实上:

For stream-based sockets, [...] message boundaries shall be ignored.

虽然这更有可能产生组合多个 "messages" 的效果,但它 可以 也意味着单个消息(由单个 send() 调用)被拆分为多个 recv() 调用。它肯定 意味着如果您指定给 recv() 的缓冲区长度小于套接字上实际接收的字节数,但在其他情况下,该结果可能也能得到。

成功时,recv() returns 复制到接收缓冲区的字节数。如果您真的想实现某种 "message" 交换,那么您可以使用它来帮助您在消息边界上拆分传入数据。但是,请务必认识到,这构成了在流之上实现消息传递协议,因此发送方和接收方需要合作,至少是隐式合作,才能使其正常工作。

John Bollinger 的回答是准确的,并提供了关于您应该如何创建可靠的客户端/服务器应用程序的见解。

关于你的问题,还有另一个问题可以解释你看到的实际输出。正如您使用 wireshark 观察到的那样,数据包很可能是在单个块中发送和接收的。该错误在您的服务器中:您在一个字符数组中接收数据并使用 printf 将其直接打印为字符串。我怀疑数据包不包含终止 '[=12=]' 以使缓冲区成为 "%s" 的正确字符串。 printf 将输出数据包内容加上那里的任何缓冲区内容,直到它到达 '[=12=]' 字节,可能会调用未定义的行为。如果数据包被分割成几个块,您可能会多次看到相同的内容,并且还会出现随机字符。

以下是您应该如何修复代码:

char buffer[2000];
...
for (;;) {
    ssize_t count = recv(mySocket, buffer, 1999, 0);

    if (count >= 1) {
        buffer[count] = '[=10=]';
        printf("Message received: |%s|", buffer);
    }
}

请注意,缓冲区必须至少比最大数据包大小长 1 个字节,并且此跟踪方法无法处理数据包中嵌入的 '[=12=]' 个字节。

当然,在客户端和服务器之间的传输过程中,数据包可以被切分,所以你必须适当地处理这个问题,以实现一个合适的协议。