关闭套接字不释放文件描述符

use*_*067 8 c++ sockets linux ulimit

当进行一些服务器代码,我写了一个压力测试,我发现,即使我的描述符句柄调用close()(和验证错误的结果)的描述符没有被释放,最终导致accept()方法返回一个错误"打开文件太多".

现在我明白这是因为ulimit,我不明白为什么如果我在每个同步接受/读/发送周期后调用close(),我会遇到它?

我通过运行带有lsof的监视来验证描述符实际上是在那里:

ctsvr  9733 mike 1017u  sock     0,7      0t0 3323579 can't identify protocol
ctsvr  9733 mike 1018u  sock     0,7      0t0 3323581 can't identify protocol
...

当然,大约有1000个左右.此外,使用netstat检查我可以看到没有挂起的TCP状态(没有WAIT或STOPPED或任何东西).

如果我只是从客户端执行单个connect/send/recv,我会注意到套接字确实保留在lsof中; 所以这甚至不是负载问题.

服务器在Ubuntu Linux 64位计算机上运行.

有什么想法吗?

use*_*067 5

因此,使用strace(感谢Gearoid),我不知道我是如何生活的,我注意到我实际上是在关闭描述符.

然而.为了后代,我露出了愚蠢的错误:

Socket::Socket() : impl(new Impl) {
    impl->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    ....
}

Socket::ptr_t Socket::accept() {
    auto r = ::accept(impl->fd, NULL, NULL);
    ...
    ptr_t s(new Socket);
    s->impl->fd = r;
    return s;
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我的构造函数立即分配了一个套接字,然后我用accept返回的描述符替换了描述符 - 创建了一个泄漏.我已经将独立的Acceptor类中的接受代码重构为Socket类而不更改它.

使用strace我可以很容易地看到每次运行socket()导致我的灯泡时刻.

谢谢大家的帮助!


phi*_*ity 0

您很可能正在执行recv()orsend()命令。考虑使用设置超时setsockopt

当另一端关闭套接字时,我注意到 lsof 上有类似的输出,但我的线程保持套接字打开挂在recv()命令等待数据上。