I/O多路转接 select 方法的使用

周梦康
  • 8.9k

下面这段代码运行没有问题和我预期的一样,程序运行之后一直阻塞,当我在终端输入内容并回车,则程序退出。但是打开注释的两行则当我在终端输入内容并回车不会退出不知道为何。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
 
int main(void)
{
    fd_set     read_set;
    int        fd1, fd2, maxfdp;
    struct     timeval time_val;
  
    fd1 = open("./test.txt",O_RDONLY);
    fd2 = open("./temp.file",O_RDONLY);
    maxfdp = fd2 + 1;
  
    FD_ZERO(&read_set);
    FD_SET(0, &read_set);
    // FD_SET(fd1, &read_set);
    // FD_SET(fd2, &read_set);
 
    time_val.tv_sec = 10;
    time_val.tv_usec = 0;
 
    while(1)
    {
 
        switch(select(maxfdp, &read_set, NULL, NULL, &time_val))
        {
            case -1:
                perror("select error:");
                break;
            case 0:
                printf("no fd prepared\n");
                break;
            default:
                for (int i = 0; i < maxfdp; ++i)
                {
                    if (FD_ISSET(i, &read_set))
                    {
                        printf("fd %d in the read_set\n", i);
                        if (i == STDIN_FILENO)
                        {
                            exit(0);
                        }
                    }
                }
                break;
        }
        sleep(1);
    }
 
    return 0;
}

测试结果:

[[email protected] unix]$ gcc select_demo.c -std=c99
[[email protected] unix]$ ./a.out
zmk
fd 0 in the read_set
[[email protected] unix]$ zmk

但是,如果打开注释的两行,则当我在终端输入回车,则不会退出。(下面的zmk是在终端的输入)

[[email protected] unix]$ gcc select_demo.c -std=c99
[[email protected] unix]$ ./a.out
fd 3 in the read_set
fd 4 in the read_set
zmk
fd 3 in the read_set
fd 4 in the read_set
zmk
fd 3 in the read_set
fd 4 in the read_set
^C
[[email protected] unix]$
回复
阅读 2.6k
1 个回答
zonxin
  • 12.1k
✓ 已被采纳

只说取消注释之后为什么不会退出。你应该知道那个为什么会退出。
select会重写read_set中的内容:select返回之后read_set中是可读的文件。由于一开始你没有输入东西(或者说你来不及输入东西,文件就可读了)所以read_set中不会包含0。而你重新调用select的时候,并没有重新把0加进去,所以以后的循环里,是不会判断0的。
需要注意的是select会重写read_set中的内容,如果你循环select,下次select之前是要重写给read_set添加值的(一般是清空之后重新添加)。

P.S. 如果一个文件“准备好”如果你一直不读(写)的话,它会一直是“准备好”的

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏