如何避免坏的FD_SET缓冲区溢出崩溃?

时间:2014-04-03 03:50:26

标签: c++ c sockets macros posix

最近我被FD_SET缓冲区溢出两次咬了。第一次是我们有太多套接字(1024+)添加到FD_SET。这是一个测试用例,我们已将其禁用,并添加assert来检测此案例。

今天,当我们运行1000多次测试用例时,我们遇到了另一个相关问题。每次,测试用例都会以某种方式触发分配套接字,然后在测试用例结束之前释放它。当我们运行1000次以上时,此测试用例将达到FD_SET缓冲区溢出。

我们找到了根本原因:

  1. 对于每次传递,分配套接字ID将增加(+1),它将不会长时间重用套接字ID。 Operating systemMAC,我认为合理的设计是避免使用已发布的套接字而不会发生错误。
  2. FD_SET仅使用套接字ID作为索引设置fd_set位数组,如果套接字ID很大,它将溢出。我认为fd_set是一个糟糕的设计。
  3. 我们认为1000+是一个合理的数字。我们不认为定义MACRO设置'fd_set'巨大是不合理的,等待时浪费内存和CPU。

    我们不知道如何解决它,所以有任何建议吗?

    ------------- ---------------- EDIT1

    事实证明在其他地方有套接字泄漏,违反析构函数应释放所有资源。这使插座ID增加。 所以第1项不是真的。操作系统将重用套接字ID。 但无论如何,讨论很有帮助,FD_SET是糟糕的设计,我们应该使用poll()

1 个答案:

答案 0 :(得分:1)

这个答案总结了OP发现的解决方案,以及rob mayoff和Joseph Quinsey的评论。

如果程序没有重用文件描述符(你称之为'socket id'),它就不会关闭文件描述符。在测试程序运行一段时间后,尝试在其上运行lsof。您可能会在输出中找到许多打开的套接字。 (但是OP说lsof -g PID似乎不适用于调试过程。)

或者,尝试netstat -a -p --inet | grep process-name-or-pid

在某些系统上,有时套接字的简单close(fd)是不够的。如果您的套接字文件描述符不断增加,那么答案close() is not closing socket properly可能会有所帮助。

为避免FD_SETSIZE出现问题,多位作者(例如Increasing limit of FD_SETSIZE and select)建议使用poll而不是select

最后,OP解决了这个问题:

  

原来在另一个地方有套接字泄漏,违反析构函数应该释放所有资源。这使得套接字ID增加。修复后,操作系统将重用套接字ID。

     

但无论如何,讨论很有帮助,FD_SET设计不好,我们应该使用poll()

请注意,类似Unix的系统总是(或通常)使用最小的可用文件描述符。例如,open(2)状态的手册页;

  

成功调用返回的文件描述符将是当前未为该进程打开的编号最小的文件描述符。