【问题标题】:socket file description套接字文件描述
【发布时间】:2012-02-23 03:04:48
【问题描述】:

所以当有人使用 select() 向我展示一些代码时,我完全失去了它:

FD_ZERO(&readfds);
FD_SET(socket,&readfds);
FD_SET(0,&readfds);
.......// bind() and listen(),regular stuff
// Before select(),this guy cleared readfds to null and sort of start all over again
FD_ZERO(&readfds);// Behold,this is exactly the line confusing myself
FD_SET(socket,&readfds);
// select will be called in the future within a infinite loop 

所以基本上说在bind和listen之后FD_ZERO是出于某种原因清除以前的内容并再次将套接字文件描述符插入fd set。同时,在fd set中,0描述符(标准输入)显然消失了。

谁能解释这整个事情?我不觉得这是正确的,但我真的无法弄清楚。也许重新设置一些特定的 fd 集是一种实用的机制......

我认为bind() 和listen() 可以以某种方式修改 fd set。我设置了几个断点并检查了输出。因此,fd set 根本没有改变。

更新:

真正让我困惑的是第二个FD_ZERO(&readfds)。 显然,第一个就像清除缓冲区中生锈的东西。在每次迭代中,我们必须将 fdset 清除为未来的默认值。我只是不明白第二个。要么是错误的,要么无论如何都不会受到伤害。

【问题讨论】:

  • select 将更改 fdset,但 bind 和 listen 不能,他们甚至没有得到指向它的指针。但请帮自己一个忙,使用像 poll 或 epoll 这样的现代 API,再也不用担心 fdset。
  • 听起来很酷,但我就是受不了
  • 使用poll。它是现代的、便携的和快速的。 epoll 仅用于自我愉悦的基准测试,它擅长的基准测试并不符合大多数实际使用需求(其中epoll 实际上比poll 慢得多)。

标签: c linux sockets


【解决方案1】:

不确定您的困惑在哪里,但这里有一个解释。

fdset 是从零开始索引的文件描述符的位掩码(从技术上讲,我认为它必须 是位掩码,但任何其他实现都会......奇怪)。

所以 fdset 可能类似于:

              Byte 0                              Byte 1
+---+---+---+---+---+---+---+---+ +---+---+----+----+----+----+----+----+
|fd0|fd1|fd2|fd3|fd4|fd5|fd6|fd7| |fd8|fd9|fd10|fd11|fd12|fd13|fd14|fd15|
+---+---+---+---+---+---+---+---+ +---+---+----+----+----+----+----+----+

这个想法是,如果您对给定的 fd(文件描述符)感兴趣,可以设置该位。如果你对它不感兴趣,你把它说清楚。

FD_ZERO 将清除所有位,这是一个很好的起点。然后两个FD_SET 调用将设置fd0(标准输入)和fd<socket> 的位。

然后,如果对标准输入有操作或对套接字有操作,则使用该 fdset 的 select 调用将返回(操作的 type 取决于您在传递 fdset 时使用的参数位置到select。将它作为读取的 fdset 传递意味着如果您可以读取套接字或标准输入上显示了某些内容(例如您使用键盘),您将返回。

这很可能在“聊天”应用程序的代码中很有用,因为它会在另一端等待您或您的朋友的输入。

您必须重新归零并重新设置 fdset 中的位的原因是,select 本身会修改该集合以指示它检测到的操作是哪个 fd(或 fds)。

示例:如果有东西通过套接字进入,而没有通过标准输入,则 fdset 将被select 修改为仅设置该位。这样您就可以使用FD_ISSET 来检测您应该查看哪些 fd。


如果,正如您在 cmets 中指出的那样,两个 FD_ZERO()/FD_SET() 序列之间有 no select 调用(或使用 readfds 的其他调用),那么,是的,看起来第一个是不必要的,因为该信息将被第二个覆盖。

没有看到完整的代码,或者架构设计文档:-),很难说。

【讨论】:

  • 让我困惑的是代码实际上两次清除 &readfds 本身。
  • @y26jin,这是因为 select 修改了数组 - 我已添加到答案中以对此进行扩展。
  • 我的意思是,第二个是在 select() 修改任何内容之前调用的。
  • 如果 std 输入和通过 socket 的 sth 什么都没有,当 select() 停止阻塞并返回时,socket 位被丢弃并且 stdinput 位仍然存在,对吗?
  • @y26jin:不完全是,相反。任何有 no 动作的位都会被清除。只有具有操作的位被设置。
【解决方案2】:

Select() 在您尝试同时侦听多个套接字时使用。每次你 'accept()' 一个套接字连接时,都会返回一个套接字描述符,你可以使用它来发送/接收文件。

当您执行FD_SET 时,您将一个套接字描述符添加到集合中(它可能是读/写的)。 FD_ZERO 清除该特定集合中的所有条目。

因此,基本上每次您接受连接时,您都可以将套接字描述符添加到集合中(也就是说,如果您想使用该套接字进行读/写)。

当您调用select() 函数时,您指定要使用的集合。 (例如:readfds)和select() 轮询已经在该集合(readfds)中的所有套接字。

如需更多说明,请阅读beej's guide to network programing。这是一个非常好的学习教程。

【讨论】:

    【解决方案3】:

    select(2) 修改其参数 fd 集,因此您应该在每次迭代时重新初始化它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-02
      • 1970-01-01
      • 2014-04-25
      • 2011-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多