我有一个侦听新连接的线程
new_fd = accept(Listen_fd, (struct sockaddr *) & their_addr, &sin_size);
和另一个在关闭程序时关闭Listen_fd的线程。然而,在Listen_fd关闭后,它仍然会阻塞。当我使用GDB尝试和调试时,accept()不会阻塞。我认为这可能是SO_LINGER的问题,但默认情况下它不应该打开,并且在使用GDB时不应该更改。有什么想法,或关闭列表套接字的任何其他建议?
答案 0 :(得分:6)
accept
调用某些非有效套接字FD的行为未定义。 “不是有效的套接字FD”包括曾经是有效套接字但后来被关闭的数字。您可能会说“但Borealid,它应该返回EINVAL!”,但这并不能保证 - 例如,相同的FD号码可能会被重新分配到close
和accept
个呼叫之间的不同套接字。 / p>
因此,即使您要隔离并纠正使程序失败的任何内容,您将来仍可能再次失败。不要这样做 - 纠正导致您尝试accept
已关闭套接字上的连接的错误。
如果您的意思是accept
之前之前的呼叫在close
之后继续阻止,那么您应该做的是发送一个发信号通知accept
中被阻止的线程。这将给它EINTR并且它可以干净地脱离 - 然后然后关闭套接字。请勿使用非使用它的线程将其关闭。
答案 1 :(得分:5)
使用:sock.shutdown (socket.SHUT_RD)
然后accept
将返回EINVAL
。不需要丑陋的十字螺纹信号!
从Python文档:
“注意close()
会释放与连接关联的资源,但不一定会立即关闭连接。如果要及时关闭连接,请在shutdown()
之前致电close()
。” / p>
http://docs.python.org/3/library/socket.html#socket.socket.close
我在C编程时遇到了这个问题。但我今天才发现解决方案,在遇到Python中的同样问题后,并使用信号进行思考(哎呀!),然后记住关于{{的注释1}}!
至于说你不应该跨线程关闭/使用套接字的注释......在CPython中,全局解释器锁应该保护你(假设你使用的是文件对象而不是原始的整数文件描述符)。
以下是示例代码:
shutdown
答案 2 :(得分:1)
这是一种解决方法,但您可以在select
上Listen_fd
超时,如果发生超时,请检查您是否要关闭该程序。如果是,退出循环,如果不是,请返回步骤1并执行下一个select
。
答案 3 :(得分:1)
您可能正在寻找shutdown()
函数。调用shutdown(Listen_fd, SHUT_RDWR)
将导致对accept()
的任何阻止的调用都返回EINVAL
。使用原子标记将对shutdown()
的调用与耦合有助于确定EINVAL
的原因。
例如,如果您具有以下标志:
std::atomic<bool> safe_shutdown(false);
然后您可以通过以下命令指示其他线程停止监听:
shutdown_handler([&]() {
safe_shutdown = true;
shutdown(Listen_fd, SHUT_RDWR);
});
为完整起见,这是您的线程如何调用accept:
while (true) {
sockaddr_in clientAddr = {0};
socklen_t clientAddrSize = sizeof(clientAddr);
int connSd = accept(Listen_fd, (sockaddr *)&clientAddr, &clientAddrSize);
if (connSd < 0) {
// If shutdown_handler() was called, then exit gracefully
if (errno == EINVAL && safe_shutdown)
break;
// Otherwise, it's an unrecoverable error
std::terminate();
}
char clientname[1024];
std::cout << "Connected to "
<< inet_ntop(AF_INET, &clientAddr.sin_addr, clientname,
sizeof(clientname))
<< std::endl;
service_connection(connSd);
}
答案 4 :(得分:0)
你在检查关闭的返回值吗? 来自linux联机帮助页,(http://www.kernel.org/doc/man-pages/online/pages/man2/close.2.html) “关闭文件描述符可能是不明智的,因为它们可能在同一进程中的其他线程中被系统调用使用。由于文件描述符可能被重用,因此有一些模糊的竞争条件可能会导致意外的副作用”。 您可以使用select而不是accept并等待来自其他thead的某个事件,然后在侦听器线程中关闭套接字。