我使用select()
来衡量服务器未接收任何新消息的时间。代码很简单,看起来像这样:
int res = -1;
do {
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
res = select(maxfd+1, &readfds, NULL, NULL, &tv);
gettimeofday(¤t, NULL);
if (get_time_diff(current, last) >= diff) {
// do something
}
} while (res <= 0);
当然,由于fd_set
只有1024位,因此不能使用超过1024个连接。幸运的是,我不需要存储所有FD,我只需要知道何时发生新连接。所以我将maxfd+1
替换为服务器FD之后的下一个数字(总是相同的,在我的情况下等于18)。
现在一切似乎都很好,并且所有客户端都从服务器获得正确的消息。但是,我不确定它是否是一个有效的解决方案,而且它肯定不是一个非常干净的解决方案。这会导致我不知道的任何问题吗?
答案 0 :(得分:1)
哎呀,select
受设计限制,fd
值超过1023
使用时不安全。
老实说,您可能无法使用select
找到重载生产服务器(如果您这样做,可能不会使用它们。)
所以我用服务器的FD之后的下一个数字替换了maxfd + 1(它总是相同的,在我的情况下等于18)。
我假设您的示例是一个最小的示例,并且您不仅仅是在查看单个监听fd
(否则,您可能只会阻止accept
,更有意义)。
这会提醒你打开另一个文件描述符* ...但是,我觉得这不是最好的方法,因为:
仅对第一个文件描述符...
执行此操作新客户端将根据第一个客户端的状态行事,他们自己的状态将被忽略,因为他们的fd
状态从未经过测试。
它使您的代码既脆弱又严格。
其他文件描述符(非套接字)可能占用特定的文件描述符,使实现完全破坏。
如果您将文件描述符添加到集合中,您仍需要测试它们的值。
更好的解决方案可能包括:
测试客户的fd
值并强制限制(if (fd >= 1024) close(fd)
)。
使用poll
(老实说,这就是它的原因 - 它是为了解决select
强加的限制而引入的。)
使用特定于操作系统的API(适用于Linux的epoll
,适用于BSD / macOS的kqueue
等)
使用抽象出特定于操作系统的API的库(例如,libev
)。
祝你好运!
* Unix样式系统保证为任何新文件描述符分配可用的最低fd
值。
这意味着您的第一个客户端将始终收到服务器+ 1(假设您没有打开或关闭任何其他文件描述符)。
但是较新的文件描述符将被赋予更高的值(除非更低的文件描述符可用)。因此,当您为第一个客户的状态进行测试时,其他客户端永远不会被轮询。