我很难描述我的问题,但上面的标题可能不明确。
我有一个普通的tcp服务器,它有一个监听套接字,最多可以接受32个客户端,我为每个客户端创建了套接字,我使用select系统调用来监控哪个客户端可以被读取,代码是一个片段我的节目。
其中,rset
是我班级的成员变量,其类型为fd_set
。我在构造函数中使用FD_ZERO
将其归零。
timeo
也是一个成员变量,类型为struct timeval
,初始化为10秒。
this->sock
也是一个成员变量,用于侦听和接受新客户端。我之前打过FD_SET(this->sock, &rset)
。
print_trace
只是一个打印邮件并附加'\ n'的宏。
while(1) {
int count = select(FD_SETSIZE, &rset, /*&wset*/ NULL, NULL, &timeo);
printf("%d fds\n", count);
if(count) {
if(FD_ISSET(this->sock, &rset)) {
// new connection comes and now this line will not blocked
if((csocks[sock_count] = accept(this->sock, NULL, NULL))) {
FD_SET(csocks[sock_count], &rset);
++sock_count;
}
} else {
print_trace("there are clients can be read.");
for(int i = 0 ; i < sock_count ; ++i) {
if(FD_ISSET(csocks[i], &rset)) {
char buffer[512] = {0};
recv(csocks[i], buffer, 512, 0);
printf("here client socket number: %d, i=%d, message: %s\n", csocks[i], i, buffer);
}
}
}
}
timeo.tv_sec = 10;
timeo.tv_usec = 0;
}
我知道我没有使用this->sock
重新启用FD_SET
,因为select会在超时时清除所有位,但它不关心我的麻烦。
我的麻烦是,当我运行服务器程序时,在10秒内,我运行客户端程序连接到此服务器,select
正常返回1,以便创建客户端套接字并添加到rset
,然后,服务器进入下一个循环,小心!现在,立即终止客户端程序,不要等待select
返回。
好的,现在问题会再次出现,服务器程序会继续打印以下信息:
1 fds
there are clients can be read.
here client socket number: 6, i=2, message:
1 fds
there are clients can be read.
here client socket number: 6, i=2, message:
1 fds
there are clients can be read.
here client socket number: 6, i=2, message:
1 fds
there are clients can be read.
here client socket number: 6, i=2, message:
...
...
我使用tcpdump
监视连接,当终止客户端时,它只发送一个FIN数据包,而服务器程序只发送一个ACK数据包,没有任何其他数据流动连接。
为什么select
可以在读取空消息时读取客户端套接字(如打印消息所示)?
任何帮助将不胜感激。
更新:我清楚地知道select
方法的用法,我以为我没有正确使用这种方法所以我花了大约一个小时研究这个方法,以解决我的问题,但发现没有结果。
答案 0 :(得分:3)
你忽略了recv()返回的结果,这本身就是一个错误,特别是你忽略了它应该关闭套接字的流为结束的零的可能性,所以你不要不要再选择EOS了。