c 中令人恼火的 select() 行为
while (xxx) {
timeout.tv_sec=TIMEOUT;
timeout.tv_usec=0;
FD_ZERO(&set);
FD_SET(sd,&set);
switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
xxxxx
}
工作正常,但
FD_ZERO(&set);
FD_SET(sd,&set);
while (xxx) {
timeout.tv_sec=TIMEOUT;
timeout.tv_usec=0;
switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
xxxxx
}
不行。 它第一次工作,但下次运行 while 循环时,即使 sd 套接字接收到数据,它也会超时。 在我看来,每次都必须清空并填充集合是对资源的浪费。
任何人都可以很好地解释为什么会出现这种情况,甚至更好,也许可以建议如何避免这种情况?
while (xxx) {
timeout.tv_sec=TIMEOUT;
timeout.tv_usec=0;
FD_ZERO(&set);
FD_SET(sd,&set);
switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
xxxxx
}
works fine, however
FD_ZERO(&set);
FD_SET(sd,&set);
while (xxx) {
timeout.tv_sec=TIMEOUT;
timeout.tv_usec=0;
switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
xxxxx
}
doesn't. It works the first time around, but the next time it runs through the while loop it gets a timeout even if the sd socket receives data. It seems to me to be a waste of resources to have to empty and fill set every time.
Anybody have a good explanation why this is, and even better, perhaps a suggestion how to avoid it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
select 修改其参数。 您确实每次都必须重新初始化它。
如果您担心开销,那么在内核中处理完整 FD_SET 的成本比 FD_ZERO 的成本要大一些。 您只想传递最大 fd,而不是 FD_SETSZIZE,以最小化内核处理。 在您的示例中:
对于具有多个 fd 的更复杂的情况,您通常最终会维护一个 max 变量:
如果您有大量文件描述符并且担心拖拽它们的开销,您应该考虑 select() 的一些替代方法。 你没有提到你正在使用的操作系统,但对于类 Unix 操作系统,有几个:
对于Solaris API 有所不同,但它们本质上都是一个有状态的内核接口,用于维护一组活动文件描述。 一旦将一个 fd 添加到集合中,您将收到该 fd 上的事件通知,而无需不断地再次传递它。
select modifies its arguments. You really do have to re-initialize it each time.
If you're concerned about overhead, the cost of processing the complete FD_SET in the kernel is somewhat more significant than the cost of FD_ZERO. You'd want to only pass in your maximum fd, not FD_SETSZIZE, to minimize the kernel processing. In your example:
For a more complex case with multiple fds, you typically end up maintaining a max variable:
If you will have a large number of file descriptors and are concerned about the overhead of schlepping them about, you should look at some of the alternatives to select(). You don't mention the OS you're using, but for Unix-like OSes there are a few:
The APIs are different, but they are all essentially a stateful kernel interface to maintain a set of active file descriptions. Once an fd is added to the set, you will be notified of events on that fd without having to continually pass it in again.
阅读选择的手册页。 返回的集合只是准备使用的文件描述符。 您应该使用 FD_ISSET 检查每一项是否已设置。
始终在使用 fd_set 之前对其进行初始化。
Read the select man page. The returned set is only the file descriptors that are ready to be used. You are supposed to use FD_ISSET to check each one if it is set or not.
Always initialize the fd_set right before using it.
这就是 select 的工作方式。 如果您有多个插座,那么它的效果最好,而且更有意义。 这就是要点:您正在许多套接字中进行选择。 如果您想从一个套接字读取数据,只需读取或接收它即可。
That's the way select works. It works best, and makes more sense, if you have more than one socket. That's kind of the point: you are selecting across many sockets. If you want to read from one socket, just read or recv it.