我有一个server
与2个连接SOCKET
,其与连接clients
和我设置该server
是非阻塞模式下发送或recieving消息时不停止。 我想设置超时时间为SOCKET
每个连接的,但如果我使用下面的代码:
void getMessage(SOCKET connectedSocket, int time){
string error = R_ERROR;
// Using select in winsock
fd_set set;
timeval tm;
FD_ZERO(&set);
FD_SET(connectedSocket, &set);
tm.tv_sec = time; // time
tm.tv_usec = 0; // 0 millis
switch (select(connectedSocket, &set, 0, 0, &tm))
{
case 0:
// timeout
this->disconnect();
break;
case 1:
// Can recieve some data here
return this->recvMessage();
break;
default:
// error - handle appropriately.
break;
}
return error;
}
我的服务器是不是没有阻塞模式的任何更多! 我要等到1日连接的时间,将其从第二连接得到消息结束了! 这不是我所期望! 那么,有没有什么办法来设置超时非阻塞模式? 还是我来处理它自己?
select
是解复用机制。 当你用它来确定数据何时准备好上的一个插槽或超时,它实际上是旨在返回的数据在许多插座就绪状态(因此fd_set
)。 从概念上讲,它是用相同的poll
, epoll
和kqueue
。 与非阻塞I / O,这些机制提供了一个应用程序编写的工具来实现单线程并发服务器相结合。
在我看来,你的应用程序并不需要这种力量。 您的应用程序将只处理两个连接,而你已经在使用每个连接一个线程。 我相信离开插座阻塞I / O模式是比较合适的。
如果你坚持非阻塞模式,我的建议是,以取代select
别的东西调用。 既然你想要什么select
是读准备就绪或超时的单个插座的指示,就可以实现具有类似效果recv
适当的参数,并与插槽上设置相应的超时过去了。
tm.tv_sec = time;
tm.tv_usec = 0;
setsockopt(connectedSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tm, sizeof(tm));
char c;
swtich (recv(connectedSocket, &c, 1, MSG_PEEK|MSG_WAITALL)) {
case -1:
if (errno == EAGAIN) {
// handle timeout ...
} else {
// handle other error ...
}
break;
case 0: // FALLTHROUGH
default:
// handle read ready ...
break;
}
从man recv
:
MSG_PEEK - 该标志将导致接收操作,从接收队列的开始,而不从队列中移除该数据返回的数据。 因此,随后的接收调用将返回相同的数据。
MSG_WAITALL(因为Linux 2.2) - 该标志请求的操作块,直到完全满足请求。 然而,该呼叫仍然可以返回如果一个信号被捕获比请求更少的数据,错误或断开时,或将要接收的下一个数据是不同类型的比返回。
至于为何select
在您观察到的方式表现。 虽然select
呼叫是线程安全的,它很可能完全防范的重入。 所以,一个线程调用select
只会另一个线程的调用完成后进来(到调用select
序列化)。 这是内联与它作为一个信号分离器的功能。 它的目的是作为一个仲裁者的哪些连接已经准备就绪。 因此,它要通过一个单独的线程控制。
文章来源: How to set time out for receiving message fromt client of server with non-blocking mode?