1

我在 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;
}

有人可以提供任何想法吗?这并不可怕,它是可行的,但它看起来像一个错误。调试消息 s 中的返回码始终为 0 - 没有错误。那么为什么会发生呢?

4

2 回答 2

1

你的问题不是 epoll 相关的,而是 socket 相关的。您不能重用该套接字的原因是它仍处于 TCPTIME_WAIT状态。这是设计上的正常行为。延迟通常是最大段生命周期的两倍,以确保在任何情况下都可以执行正确关闭的完整往返,但也可以使用SO_LINGER. 您可能很想简单地配置SO_LINGER成更短的东西,但不要那样做。不建议使用此表盘,因为它可能会干扰正常、正常的关机。

另一个选项是设置SO_REUSEADDR套接字选项,这可能是您想要的。请注意,它SO_REUSEADDR告诉套接字层忘记它所做的正确性承诺,并故意破坏正常的可操作性。基本上你是在告诉你的网络库:“是的,我知道这样做是错误的,但我保证没有人再关心那个套接字,也不会发生任何邪恶的事情”
这正是您的示例中的情况。您已经以艰难的方式关闭了套接字,它已经消失了,没有其他人在使用它,您所关心的只是尽快重新使用它。

有关可用套接字选项的描述,请参见socket(7)例如。

于 2014-10-24T10:43:27.320 回答
1

我猜你不能重复使用套接字,因为你需要向系统请求它。在调用 bind(2) 之前,请执行以下操作:

https://github.com/edsiper/monkey/blob/master/src/mk_socket.c#L114

我希望它有帮助。

于 2013-02-14T19:10:14.490 回答