最近我被FD_SET
缓冲区溢出两次咬了。第一次是我们有太多套接字(1024+)添加到FD_SET
。这是一个测试用例,我们已将其禁用,并添加assert
来检测此案例。
今天,当我们运行1000多次测试用例时,我们遇到了另一个相关问题。每次,测试用例都会以某种方式触发分配套接字,然后在测试用例结束之前释放它。当我们运行1000次以上时,此测试用例将达到FD_SET
缓冲区溢出。
我们找到了根本原因:
Operating system
是MAC
,我认为合理的设计是避免使用已发布的套接字而不会发生错误。FD_SET
仅使用套接字ID作为索引设置fd_set
位数组,如果套接字ID很大,它将溢出。我认为fd_set
是一个糟糕的设计。我们认为1000+是一个合理的数字。我们不认为定义MACRO设置'fd_set'巨大是不合理的,等待时浪费内存和CPU。
我们不知道如何解决它,所以有任何建议吗?
------------- ---------------- EDIT1
事实证明在其他地方有套接字泄漏,违反析构函数应释放所有资源。这使插座ID增加。
所以第1项不是真的。操作系统将重用套接字ID。
但无论如何,讨论很有帮助,FD_SET
是糟糕的设计,我们应该使用poll()
。
答案 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)
状态的手册页;
成功调用返回的文件描述符将是当前未为该进程打开的编号最小的文件描述符。