我的问题是我有一个在recv()调用中的线程.远程主机突然终止(没有close()套接字调用)并且recv()调用继续阻塞.这显然不是很好,因为当我加入线程来关闭进程(本地)时,这个线程将永远不会退出,因为它正在等待永远不会来的recv.
所以我的问题是人们通常认为什么方法是处理这个问题的最佳方法?在回答之前还应该知道一些额外的注意事项:
在退出之前,我无法确保远程主机关闭套接字.
此解决方案无法使用外部库(例如boost).它必须使用C++/C的标准库/功能(最好不是特定于C++ 0x).
我知道这可能在过去曾被问过,但是我想知道如何正确地解决这个问题(没有做过去我本来会做的超级hacky).
谢谢!
假设您要继续使用阻塞套接字,可以使用SO_RCVTIMEO
套接字选项:
SO_RCVTIMEO and SO_SNDTIMEO
Specify the receiving or sending timeouts until reporting an
error. The parameter is a struct timeval. If an input or out-
put function blocks for this period of time, and data has been
sent or received, the return value of that function will be the
amount of data transferred; if no data has been transferred and
the timeout has been reached then -1 is returned with errno set
to EAGAIN or EWOULDBLOCK just as if the socket was specified to
be nonblocking. If the timeout is set to zero (the default)
then the operation will never timeout.
Run Code Online (Sandbox Code Playgroud)
所以,在你开始接收之前:
struct timeval timeout = { timo_sec, timo_usec };
int r = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
assert(r == 0); /* or something more user friendly */
Run Code Online (Sandbox Code Playgroud)
如果您愿意使用非阻塞I/O,那么你可以使用poll()
,select()
,epoll()
,kqueue()
,或其他适当的事件调度机制是为您的系统.您需要使用非阻塞I/O的原因是您需要允许系统调用recv()
返回以通知您套接字的输入队列中没有数据.使用的示例涉及更多:
for (;;) {
ssize_t bytes = recv(s, buf, sizeof(buf), MSG_DONTWAIT);
if (bytes > 0) { /* ... */ continue; }
if (bytes < 0) {
if (errno == EWOULDBLOCK) {
struct pollfd p = { s, POLLIN, 0 };
int r = poll(&p, 1, timo_msec);
if (r == 1) continue;
if (r == 0) {
/*...handle timeout */
/* either continue or break, depending on policy */
}
}
/* ...handle errors */
break;
}
/* connection is closed */
break;
}
Run Code Online (Sandbox Code Playgroud)