Recv()调用在远程主机终止后挂起
Recv() call hangs after remote host terminates
我的问题是,我有一个线程是在一个recv()调用。远程主机突然终止(没有close()套接字调用),recv()调用继续阻塞。这显然不是很好,因为当我连接线程来关闭进程(本地)时,这个线程将永远不会退出,因为它正在等待一个永远不会来的recv。
所以我的问题是,人们通常认为处理这个问题的最好方法是什么?在回答问题之前,还需要知道一些额外的注意事项:我无法确保远程主机在退出之前关闭套接字。
此解决方案不能使用外部库(如boost)。它必须使用c++/C的标准库/特性(最好不是c++ 0x特定的)。
我知道过去可能有人问过这个问题,但我希望有人能告诉我如何正确地纠正这个问题(而不是做一些我过去会做的超级黑客的事情)。
谢谢!
假设您想继续使用阻塞套接字,您可以使用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.
所以,在你开始接收之前:
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 */
如果您愿意使用非阻塞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;
}
您可以使用TCP保持活动探测来检测远程主机是否仍然可达。当启用keep-alive时,如果连接空闲时间过长,操作系统将发送探针;如果远程主机不响应探测,则关闭连接。
在Linux操作系统上,可以通过设置SO_KEEPALIVE
套接字选项来启用keep-alive探测,可以通过设置TCP_KEEPCNT
、TCP_KEEPIDLE
和TCP_KEEPINTVL
套接字选项来配置keep-alive的参数。更多信息请参见tcp(7)
和socket(7)
。
Windows也使用SO_KEEPALIVE
套接字选项来启用keep-alive探测,但要配置keep-alive参数,请使用SIO_KEEPALIVE_VALS
ioctl.
可以使用select()
从http://linux.die.net/man/2/selectint select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
select()阻塞,直到一个或多个文件描述符上的第一个事件(读准备好、写准备好或异常)或超时发生。
sockopt和select
可能是理想的选择。您应该考虑作为备份的另一个选项是向进程发送一个信号(例如使用alarm()
调用)。这将强制任何正在进行的系统调用退出,并将errno
设置为EINTR
。
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 我收到以下错误:抛出'std::bad_alloc'实例后终止调用
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它
- EvtExportLogneneneba API正在将远程计算机的事件日志保存到远程PC本身.如何将其保存到主机
- 为什么这个 c++ 代码打印出长度 5,当我打印出字符串时,程序会自动终止?
- 当我在其中一个线程执行中(在activemq-cpp中)捕获到特定值时,我如何终止/停止所有其他线程
- llvm构建器向基本块添加终止符
- 如何使用隔离>终止执行来停止所有线程
- 用于将C++代码转换为 Web 程序集的脚本未终止
- C++应用程序 MySQL odbc 数据库连接错误:在引发"otl_tmpl_exception<>"实例后终止调用
- 终止 QProcess 不会终止子进程
- 如何停止 CLR 主机?
- 运行代码时,c++ 会终止进程
- 如何强制 Thrift 仅接受来自本地主机的连接
- 检测到堆栈粉碎:已终止 中止(核心已转储)
- 在输入句子时终止 std::out_of_range
- 二进制搜索的终止点
- Windows 脚本主机在关闭创建的窗口时终止
- Recv()调用在远程主机终止后挂起