I/O 多路转接 select
读一个文件描述符写另一个文件描述符时迫切需要
int select (int maxfdp1,fd_set *restrict readfds,fd_set * restrict writefds,fd_set * restrict exceptfds,struct timeval * restrict tvptr);
readfds,writefds,execptfds 是我们关心的可读可写 和异常的文件描述符集合
maxfdp1 表示最大文件描述符号+1的数
tvptr==null 永远等待
tvptr->tv_sec==0&&tvptr->usec==0 不等待 直接检测
文件描述符集合需要用一下几个函数:
int FD_ISSET(int fd,fd_set *fdset); //检测是否是 打开状态 select 函数返回时候
void FD_CLR(int fd,fd_set *fdset); //将某一位关闭
void FD_SET(int fd,fd_set *fdset); //将某一位开启
void FD_ZERO(fd_set * fdset); //将一个fsd_set 变量所有位设置为0 初始化时候使用
需要注意的是 每次调用select函数的之前 都需要 初始化和设置fd_set
void relay(int fd1,int fd2) { struct fsm_st fsm12,fsm21; int fd1_save,fd2_save; fd_set rset,wset; fd1_save = fcntl(fd1,F_GETFL);//获取文件描述符状态 fcntl(fd1,F_SETFL,fd1_save|O_NONBLOCK);//加上为阻塞状态 fd2_save = fcntl(fd2,F_GETFL); fcntl(fd2,F_SETFL,fd2_save|O_NONBLOCK); fsm12.state = STATE_R; fsm12.sfd = fd1; fsm12.dfd = fd2; fsm21.state = STATE_R; fsm21.sfd = fd2; fsm21.dfd = fd1; while(fsm12.state != STATE_T || fsm21.state != STATE_T) { /*布置监视任务*/ FD_ZERO(&rset); FD_ZERO(&wset); if(fsm12.state == STATE_R) FD_SET(fsm12.sfd,&rset); if(fsm12.state == STATE_W) FD_SET(fsm12.dfd,&wset); if(fsm21.state == STATE_R) FD_SET(fsm21.sfd,&rset); if(fsm21.state == STATE_W) FD_SET(fsm21.dfd,&wset); /*监视*/ if(fsm12.state < STATE_AUTO || fsm21.state < STATE_AUTO) { if(select(max(fd1,fd2)+1,&rset,&wset,NULL,NULL) < 0) { if(errno == EINTR) continue; perror("select()"); exit(1); } } /*查看监视结果*/ if(FD_ISSET(fd1,&rset) || FD_ISSET(fd2,&wset) || fsm12.state > STATE_AUTO) fsm_driver(&fsm12); if(FD_ISSET(fd2,&rset) || FD_ISSET(fd1,&wset) || fsm21.state > STATE_AUTO) fsm_driver(&fsm21); } fcntl(fd1,F_SETFL,fd1_save);//还原文件描述符状态 fcntl(fd2,F_SETFL,fd2_save); }