我在Ubuntu Linux内核3.5.0-23上编写了一个epoll服务器,运行良好,遇到一个问题: 如果客户端连接,然后注销,我可以立即重启服务器。 但是,如果客户端仍然连接并关闭服务器,他将被断开连接,但端口仍然会被绑定X秒(不能告诉X,我会说它大概是20)。 如果我用编译器终止程序,也会发生这种情况。
关闭时,我使用了与客户离开时相同的功能:
int CEpollClient::Close ()
{
if(m_socket!=SOCKET_ERROR)
{
int res=::epoll_ctl (m_server_handler, EPOLL_CTL_DEL, m_socket, 0);
_debug_message("client exits");
_debug_message(res);
shutdown(m_socket,SHUT_RDWR);
::close (m_socket);
m_socket=SOCKET_ERROR;
}
return 0;
}
这是客户端类的一部分,所以这个完全相同的代码被调用,无论我是在他自己离开或初始化之后关闭客户端。 我在关闭服务器时也关闭了侦听套接字:
if (m_listener != SOCKET_ERROR)
{
_debug_message("stop listener");
code=epoll_ctl(m_epoll_handler,EPOLL_CTL_DEL,m_listener,0);
_debug_message(code);
shutdown(m_listener,SHUT_RDWR);
::close(m_listener);
m_listener = SOCKET_ERROR;
}
有人可以提出任何想法吗?这并不可怕而且可行,但看起来确实像个bug。 调试消息中的返回码始终为0 - 没有错误。 那么为什么会这样呢?
答案 0 :(得分:1)
我猜您无法重新使用套接字,因为您需要向系统请求它。在调用bind(2)之前做这样的事情:
https://github.com/edsiper/monkey/blob/master/src/mk_socket.c#L114
我希望它有所帮助。
答案 1 :(得分:1)
你质疑与epoll无关,但与套接字有关。你不能重用那个套接字的原因是它仍然在TCP TIME_WAIT
状态中挥之不去。这是正常行为,按设计。延迟通常是最大段寿命的两倍,以确保在任何情况下都可以执行完整的往返以执行正确的关闭,但它也可以使用SO_LINGER
进行配置。您可能很想简单地将SO_LINGER
配置为更短的内容,但不要这样做。使用此拨号是不可取,因为它可能会干扰正常,正常的关机。
另一种选择是设置SO_REUSEADDR
套接字选项,这可能就是你想要的。请注意SO_REUSEADDR
告诉套接字层忘记它所做的正确性承诺并故意破坏正常的可操作性。基本上你是在告诉你的网络库:“是的,我知道这样做是错的,但我保证不再关心那个插座而且不会发生任何邪恶的事情”。
这正是你的例子中的情况。你已经用困难的方式关闭了套接字,它已经消失了,没有其他人在使用它,而你所关心的只是尽快重新使用它。
有关可用套接字选项的说明,请参阅socket(7)
,例如。