我有一个程序作为一个简单的tcp服务器,它将接受并服务多达4个客户端。我编写了以下代码片段来存档这个目标,为了更清楚,我用"幻数"替换了一些MACRO。
while(1) {
int ret = 0;
///
// sock_ is the listening socket, rset_conn_ only contains sock_
//
if(select(sock_ + 1, &rset_conn_, NULL, NULL, &timeo_) <= 0) {
ret = 0;
}
if(FD_ISSET(sock_, &rset_conn_)) {
ret = 1;
}
///
// because the rule select() clears file descriptor and updates timeout is
// complex, for simplicity, let's reset the sock_ and timeout
//
FD_SET(sock_, &rset_conn_);
timeo_.tv_sec = 0;
timeo_.tv_usec = 500000;
if(! ret) {
continue ;
}
///
// csocks_ is an 4 integer array, used for storing clients' socket
//
for(int i = 0 ; i < 4 ; ++i) {
if((-1 == csocks_[i]) && (-1 != (csocks_[i] = accept(sock_, NULL, NULL)))) {
break ;
}
}
}
现在,当少于4个客户端连接时,此代码段正常工作,但是当第5个客户端连接时,正如您所看到的, for 循环中不会接受它,这会导致这样的问题:在 while 的以下循环中,select()调用继续返回 rset_conn _ 集中的 sock _ 位 - 只是因为我不接受!!
我意识到我不应该在 for 循环中忽略它(不接受),但是如何通过告诉内核&#34来正确处理它;我不想要接受这个客户,所以不要告诉我这个客户想再联系我了!&#34;?
任何帮助将不胜感激..
更新
我无法停止调用select()调用,因为已经连接的客户端可能断开连接,然后我的程序将有新的客户端空间。我需要保持监听套接字以接受连接,而不是在达到一点时停止侦听。
答案 0 :(得分:5)
为什么你问一个你不想要答案的问题?如果您不想被告知存在未接受的连接,请停止在收听套接字上拨打select
。
我无法停止调用select()调用,因为已经连接的客户端可能断开连接,然后我的程序将有新的客户端空间。我需要继续监听套接字以接受连接,而不是在达到一点时停止监听。
您可以停止立即调用选择。当客户端断开连接时,再次开始调用select
。只提出你想要答案的问题。
答案 1 :(得分:3)
没有套接字API来告诉内核忽略挂起的连接(在Windows上,WSAAccept()
中有回调,但这是Microsoft特定的扩展名。)
在大多数平台上,您必须:
close()
监听套接字,然后在客户端断开连接时重新打开它。
accept()
客户端,但如果数组已满,则立即close()
。
在阵列已满时停止呼叫select()
和accept()
。积压中的任何客户端最终都会超时,除非您的阵列填满,并且accept()
待处理的客户端超时之前。
答案 2 :(得分:2)
当有四个现有客户端时,您可以从readFD中删除侦听套接字,并在一个客户端丢弃时将其放回,但我不明白这一点。为什么只有四个客户?为什么不删除限制并消除整个问题?真正的服务器不是以这种方式构建的。