IO多路转接select和poll

select

IO多路复用的设置方法与信号的屏蔽有点相似:
信号屏蔽需要先设定一个信号集, 初始化信号集, 添加需要屏蔽的信号, 然后用sigprocmask设置
IO多路转接需要先设定一个文件描述符集, 初始化描述符集, 添加感兴趣的描述符, 然后用select进行轮询检测哪些描述符已经可用

描述符集相关函数:

fd_set //描述符集
int FD_ZERO(fd_set*)// 清空fd_set
int FD_SET(fd,fd_set*)// 将fd添加到fd_set中
int FD_CLR(fd,fd_set*)// 从fd_set中删除fd
int FD_ISSET(fd,fd_set*)// select返回后, 判断fd_set中的fd是否已经可用

int select(int maxfdp1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *tvptr)
maxfdp1: 最大文件符编号(fd)+1, 或直接用FD_SETSIZE
readfds: 感兴趣的输入描述符集
writefds: 感兴趣的输出描述符集
exceptfds: 感兴趣的错误输出描述符集
struct timeval{
    time_t tv_sec; //秒 long int
    suseconds_t tv_usec; //微秒 long int
}
select最后一个参数为NULL, 表示无限等待; 为0时(timeval结构成员设置成0), 不等待; 不为0时(timeval指定值)时等待指定的时间后返回

例子: 从STDIN_FILENO读

#include "apue.c"
#include <sys/select.h>
 
int main(){
    int ret, len;
    fd_set set;
    struct timeval time_out={5,0};
    while(1){
        FD_ZERO(&set);
        FD_SET(STDIN_FILENO,&set);
        time_out.tv_sec=5;
        time_out.tv_usec=0; 
 
        ret=select(1,&set,NULL,NULL,&time_out);
        switch(ret){
            case 0:
                puts("time out, retry");
                continue;
            case -1:
                err_quit("select err");
            default:
                if(FD_ISSET(STDIN_FILENO,&set)){
                    puts("STDIN_FILENO is available");
                    char buf[100]={0};
                    len=read(STDIN_FILENO,buf,100);
                    write(STDOUT_FILENO,buf,len);
                }
        }
    } 
    return 0;
}

注意:select 返回后, 传入的fd_set和timeval会改变, 所以当重新调用select时要再次初始化fd_set和timeval
另外还有一个与select相似的函数叫pselect

int pselect(int maxfd1, fd_set *readfds, fd_set *writefds, fd_set exceptfds, const struct timespec *tsptr, const sigset_t *sigmask)

与select不同的地方: pselect的等待时间设置结构为timespec, 且被调整为const, pselect还可以设置进程信号屏蔽

poll

与select作用相同, 实现不同
poll第一个参数是一个fd数组集合, 每个fd关联一个pollfd结构, 该结构说明fd的关心状态是读还是写
poll第二个参数是第一个参数中fd的个数
poll第三个参数是等待时间, -1表示无限等待, 0表示不等待, 其它正值表示可等待的毫秒数

int poll(struct pollfd fdarray[], unsigned int nfds, int timeout);
struct pollfd{
    int fd;
    short events; //常用的读POLLIN/写POLLOUT
    short revents; //可忽略设置
}
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/poll.h>
 
int main(int argc, char *argv[]){
    char buf[1024];
    int fd;
    int i;
    struct pollfd pfds[2];
    fd=open(argv[1],O_RDONLY);
 
    while(1){
        pfds[0].fd=STDIN_FILENO;
        pfds[0].events=POLLIN;
 
        pfds[1].fd=fd;
        pfds[1].events=POLLIN;
 
        poll(pfds,2,-1);
        if(pfds[0].revents & POLLIN){
            i=read(STDIN_FILENO,buf,1024);
            write(STDOUT_FILENO,buf,i);
        }
 
        if(pfds[1].revents & POLLIN){
            i=read(fd,buf,10);
            write(STDOUT_FILENO,buf,i);
        }
    }
}
原文地址:https://www.cnblogs.com/cfans1993/p/5701324.html