我写了一个服务器,应该在打开与客户端的连接之后等待来自客户端的消息:
while(1){
if(recv(mySocket, buffer, 1000, 0) < 1){
continue;
}
printf("Message received: %s", buffer);
}
我使用wireshark检查了哪些数据包被发送到此服务器,但是每发送一个数据包都有2个printf输出。
我现在的问题是从哪里获得这条额外的消息。
(附加消息是一些随机字节。但每次都是相同的。)
答案 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'
字节。
当然,数据包可以在客户端和服务器之间的路上进行切片和切块,因此您必须适当地处理它以实现正确的协议。