只发送一封消息,从接收中获取两条消息

时间:2015-05-31 13:29:14

标签: c sockets networking

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

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

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

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

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

2 个答案:

答案 0 :(得分:2)

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

  

对于基于流的套接字,应忽略消息边界。

虽然这更有可能产生组合多个&#34;消息&#34;的效果,但 也意味着单个消息(由单个{{{ 1}} call)分为多个send()个调用。当然意味着如果您指定给recv()的缓冲区长度小于套接字上实际接收的字节数,但是在其他情况下可以获得该结果,太

成功时,recv()返回复制到接收缓冲区的字节数。如果你真的想要实现某种&#34;消息&#34;交换,然后您可以使用它来帮助您在消息边界上分割传入的数据。但要注意,这构成了在流之上实现消息传递协议,因此发送方和接收方需要合作,至少是隐含的,才能使其工作。

答案 1 :(得分:0)

John Bollinger的回答非常准确,可以深入了解您应该如何创建可靠的客户端/服务器应用程序。

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

以下是修复代码的方法:

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

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

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

当然,数据包可以在客户端和服务器之间的路上进行切片和切块,因此您必须适当地处理它以实现正确的协议。