在C语言中使用select()函数后如何知道哪些文件描述符是可用的?

4
我对套接字编程不是很熟悉,最近被引入了`select()`系统调用。我的问题是,比如说我正在用C语言编写服务器(这正是我尝试做的),我想在实现中使用`select()`调用进行练习。我正在尝试编写一个从客户端接收信息的服务器,所以我的方法是使用`select()`,然后使用`read()`来输出信息。
根据我读到的文档,`select()`会返回输入集合中准备好进行i/o操作的文件描述符数量。我的问题是,怎么知道原始集合中哪个文件描述符已经准备好进行i/o操作?我似乎在搜索和查看了一段时间的示例后找不到答案。
假设我代码如下:
int main() {
/* Create socket/server variables */
    int select_value;
    int this_socket;
    int maxfd;
    struct sockadder_in address; 
    fd_set allset;

    /* Bind the socket to a port */
    main_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (main_socket < 0) {
        perror("socket()");
        exit(1);
    }

    Connect(main_socket, (struct sockaddr *)&address, sizeof(address));

    /* Add the socket to the list of fds to be monitored */
    FD_ZERO(&allset);
    FD_SET(main_socket, &allset);

    fd_set read_ready = allset;
    fd_set write_ready = allset;

    while (1) {
        /* Listen for a connection */
        /* Accept a connection */
        select_value = Select(maxfd+1, &read_ready, &write_ready, NULL, NULL);
        if (select_value == -1) {
            perror("select()");
            exit(1);
        }
        else if(select_value > 0) {
            /* How to access i/o ready file descriptors
            now that we know there are some available? */
        }
    }
} 

我一定会考虑在未来的实践项目中尝试它,谢谢你的建议! - thanos
4
考虑使用poll(2)代替较旧的select。 搜索"C10K问题"。 - Basile Starynkevitch
请仔细阅读RTFM,特别是selectselect_tut的手册页。 - Ulrich Eckhardt
1个回答

4

可以使用 <sys/select.h> 中的 FD_ISSET 宏来实现此操作。

当您的 select 调用解除阻塞并且文件描述符已准备就绪时,您可以使用简单循环中的 FD_ISSET 宏测试所有文件描述符。以下示例展示了如何实现:

for (i = 0; i < FD_SETSIZE; ++i) {
    if (FD_ISSET (i, &read_fd_set)) {
        if (i == bound_socket) {
            // A new client is waiting to be accepted
            new = accept(sock, (struct sockaddr *) &clientname, &size);
            // ...
            FD_SET (new, &active_fd_set);
        }
        else {
          // There is something to be read on the file descriptor.
          data = read_from_client_on(i);
        }
    }
}

当然,这只是一个示例,显然缺乏任何错误处理,您需要在应用程序中处理它。

非常感谢,这是一个简单明了的解释。我忘记了select()是作为位掩码实现的,所以在看到你的解释和循环之前,我不理解FD_SET的用法。 - thanos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接