套接字编程新手,有关 "select()" 的问题

New to socket programming, questions regarding "select()"

目前在我的学位课程中,我们开始使用套接字。

我有几个关于从套接字轮询输入的问题,

使用 select() 函数。

int select( int nfds,
    fd_set *readfds,
    fd_set *writefds,
    fd_set *exceptfds,
    const struct timespec *timeout);
  1. 我们给 select "nfds" 参数,这通常会 是我们想要监控的最大套接字数。我怎样才能只看一个特定的套接字而不是 0 到 nfds_val 套接字的范围?

  2. 我们使用的文件描述符对象是什么?他们的目的是什么, 为什么我们不能直接将 "select" 指向相关的套接字结构?

  3. 我在论坛上阅读了有关 阻塞非阻塞 模式的 select ,但不明白每个的含义或用途,也不知道如何实现,如果有人能解释一下,我会很高兴。

  4. 最后但并非最不重要的(仅暂时:D)-将socketaddr_in绑定到套接字编号时,为什么需要转换为socketaddr * 而不是将其保留为 sockaddr_in * ? 我的意思是除了 bind 方法需要这种指针类型之外;)

在此感谢一些专家的回答:)

谢谢你们,祝大家度过愉快的一周!

We give select "nfds" param, which would normally would be the maximum sockets number we would like to monitor. How can i watch only one specific socket instead of the range of 0 to nfds_val sockets ?

Edit.(抱歉,这里之前的文字有误)只需提供您的插座descriptor + 1。我很确定这并不意味着 OS 将检查 [0, 1... descriptor] 范围内的所有描述符。

What are the file descriptors objects that we use? what is their purpose, and why can't we just point "select" to the relevant socket structure?

文件描述符通常是由 OS 提供给用户的整数值。 OS 使用描述符来控制物理和逻辑资源 - 一个文件描述符意味着 OS 已经给了你一些 file-like 来控制。由于 Berkeley 套接字定义了读写操作,因此它们是 file-like 并且套接字对象本质上是普通文件描述符。

回答why can't we just point "select" to the relevant socket structure? - 我们确实可以。传递给 select 的具体内容取决于 OS 和语言。在 C 中,您将套接字描述符(最有可能是普通 int 值)放入 fd_setfd_set 然后传递给 select.

编辑。 Linux:

的一个小例子
fd_set set;
FD_ZERO(&set);
FD_SET(socket_fd, &set);
// check if socket_fd is ready for reading
result = select(socket_fd + 1, &set, NULL, NULL, NULL);  
if (result == -1) report_error(errno);

Docs.
Windows has similar code.

I've read over the forum regarding Blocking and Non-Blocking mode of select, but couldn't understand the meaning or uses of each, nor how to implement such, would be glad if someone could explain.

阻塞 操作使您的线程等待完成。这是您使用的 99% 的功能。如果有套接字准备好进行某些 IO,阻塞 select 将立即 return something。如果没有这样的套接字,线程将等待它们。 Non-blocking select,在后一种情况下,不会等待,会return -1(错误)。

例如,尝试实现能够与多个客户端一起工作的单线程服务器,包括同时发生的文件传输等长时间操作。在这种情况下,您绝对不想使用阻塞套接字操作。

Last but not least (only for the time being :D ) - When binding a socketaddr_in to socket number, why does one needs to cast to socketaddr * and not leave it as sockaddr_in * ? I mean except for the fact that bind method expects this kind of pointer type ;)

可能是由于历史原因,但我不确定。 And there seems to be a fine answer on SO already.