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

时间:2012-10-10 13:51:07

标签: c++ linux sockets 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位计算机上运行。

有什么想法吗?

3 个答案:

答案 0 :(得分: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;
}

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

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

谢谢大家的帮助!

答案 1 :(得分:1)

你有没有在close()之后调用perror()? 我认为返回的字符串会给你一些帮助;

答案 2 :(得分:0)

您最有可能挂在recv()send()命令上。考虑使用setsockopt设置超时。

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