我目前正在开展一个涉及多个客户端连接到服务器并等待数据的项目。我正在使用select和监视传入数据的连接。但是,客户端只是继续打印任何内容,就像select已发现传入数据一样。也许我正在攻击这个错误?
对于服务器发送的第一条数据,它会正确显示。但是,服务器然后断开连接,客户端继续喷出空白行。
FD_ZERO(&readnet);
FD_SET(sockfd, &readnet);
while(1){
rv = select(socketdescrip, &readnet, NULL, NULL, &timeout);
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Connection timeout! No data after 10 seconds.\n");
} else {
// one or both of the descriptors have data
if (FD_ISSET(sockfd, &readnet)) {
numbytes = recv(sockfd, buf, sizeof buf, 0);
printf("Data Received\n");
buf[numbytes] = '\0';
printf("client: received '%s'\n",buf);
sleep(10);
}
}
}
答案 0 :(得分:4)
我认为您需要检查recv
的结果。如果它返回零,我相信这意味着服务器已关闭套接字。
另外(取决于具体实施),您可能需要将socketdescrip+1
传递给select
。
答案 1 :(得分:2)
如果我没记错,您需要在每次调用fd
之前初始化一组select()
,因为select()
会破坏它。
所以在FD_ZERO()
之前移动FD_SET()
和select()
。
答案 2 :(得分:1)
表现得好像已经发现了 传入的数据。也许我正在攻击 这错了?
除了前面所说的之外,我还要注意select()/ poll()确实告诉你“数据何时存在”,而不是下一个相应的系统调用不会阻塞。而已。如上所述,recv()不会阻塞并正确返回0,这意味着EOF,连接被另一方关闭。
虽然在大多数* nix系统中只有第一次调用recv()会返回0,但是后面的调用会返回-1。使用异步I / O时,必须进行严格的错误检查!
我个人强烈建议改用poll()。与select()不同,它不会破坏其参数,并且可以使用高编号的套接字描述符。
答案 3 :(得分:1)
当服务器关闭连接时,它会向客户端发送一个带有FIN标志的数据包,宣布它不再发送数据。数据包由客户端的TCP / IP堆栈处理,没有应用程序级别的数据。通知应用程序级别触发select,因为监视文件描述符上发生了某些事情,而recv()返回0字节,因为服务器没有发送数据。
答案 4 :(得分:0)
谈论你的代码时,这是真的吗?
select(highest_file_descriptor+1, &readnet, NULL, NULL, &timeout);
在你的简单例子中(如qrdl所说,FD_ZERO和FD_SET在while(1)循环内移动)它应该如下所示:
select(sockfd+1, &readnet, NULL, NULL, &timeout);
另外 - 请注意,当recv返回0字节时,它意味着连接已关闭 - 没有更多数据!你的代码也有错误 - 当recv发生错误时(当发生这种情况时返回< 0)你将遇到严重问题,因为像buf [-1]这样的东西可能导致不可预测的结果。请妥善处理此案。
虽然我尊重您尝试使用低级BSD套接字API这一事实,但我必须说我发现它非常低效。这就是为什么我建议你尽可能使用ACE这是一个非常有效和高效的框架,在网络编程方面已经实现了很多东西(例如ACE_Reactor可以更容易地做什么你想在这里实现。)