select
提供的方法:清除,判断,添加,清零。
类似信号的sigemptyset
目录:adv/select 拷贝relay.c 两个设备通信 忙等 更改程序 while 忙等 更改。布置监视任务
- select 可以做安全的休眠 设置 -1 nfd;
#include <stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define BUFSIZE 1024
enum
{
STATE_R=1,
STATE_W,
STATE_Ex,
STATE_T
};
struct fsm_st
{
int state;
int sfd;
int dfd;
char buf[BUFSIZE];
int len;
int pos;
char *errstr;
};
static void fsm_driver(struct fsm_st *fsm)
{
int ret;
switch(fsm->state)
{
case STATE_R:
fsm->len=read(fsm->sfd,fsm->buf,BUFSIZE);
if(fsm->len==0)
fsm->state=STATE_T;
else if(fsm->len <0)
{
//真错与假错
if(errno==EAGAIN)
fsm->state=STATE_R;
else
{
fsm->errstr="read()";
fsm->state=STATE_Ex;
//跳转同时记录出错原因
}
}
else
{
fsm->pos=0;
fsm->state=STATE_W;
}
break;
case STATE_W:
ret=wirte(fsm->dfd,fsm->buf+fsm->pos,fsm->len);
if(ret<0)
{
if(errno=EAGAIN)
fsm->state=STATE_W;
else
{
fsm->errstr="write()"
fsm->state=state_Ex;
}
}
else
{
fsm->pos+=ret;
fsm->len-=ret;
if(fsm->len==0)
fsm->state=STATE_R;
else
fsm->state=STATE_W;
}
break;
case STATE_Ex:
//报错
perror(fsm->errstr);
fsm->state=STATE_T;
break;
case STATE_T:
//进程结束 但是结束不了 死循环 do sth
break
default:
//do sth 信号
abort();
break;
}
}
static int max(int a, int b)
{
if(a>b)
return a;
return b;
}
static void relay(int fd1,int fd2)
{
int fd1_save,fd2_save;
struct fsm_st fsm12,fsm21; //读1写2&&读2写1
fd_set rset,wset;
int fd1_save,fd2_save;
//两个文件描述符 以非阻塞打开
fd1_save=fcntl(fd1,F_GETFL);
fcntl(fd1,F_SETFL,fd1_save|O_NONBLOK);
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);
rset,wset;
//进行监视
if(select(max(fd1,fd2)+1,&rset,&wset,NULL,NULL)<0)//null 为忙等的时间
{
if(errno == EINTR)
continue;//假错
perror("select()");
exit(1);
}
//查看监视结果
//有条件的推动 发生感兴趣的动作
if(FD_ISSET(fd1,&rset)||FD_ISSET(fd2,&wset))
fsm_driver(&fsm12); //fd1可读 fd2可写
if(FD_ISSET(fd2,&rset)||FD_ISSET(fd1,&wset))
fsm_driver(&fsm21);
}
//文件状态恢复
fcntl(fd1,F_SETFL,fd1_save);
fcntl(fd2,F_SETFL,fd2_save);
}
select 用来监视文件描述符的行为,当文件描述符发生了感兴趣的行为或者达到了感兴趣的状态 函数返回 有目的地推动状态机 没有考虑到异常处理状态 加一条线 当前状态>3 ex推动到t态 无条件推动;线上有条件推动 线下为无条件推动
enum
{
STATE_R=1,
STATE_W,
STATE_AUTO,
STATE_Ex,
STATE_T
}
//监视的时候
//读写的状态 才监视
if(fsm12.state<STATE_AUTO || fsm21.state<STATE_AUTO)
{
...
}
//查看监视结果
if(FD_ISSET(fd1,&rset)||FD_ISSET(fd2,&wset)||fsm12.state>STATE_AUTO)
fsm_driver(&fsm12); //fd1可读 fd2可写
if(FD_ISSET(fd2,&rset)||FD_ISSET(fd1,&wset)||fsm21.state>STATE_AUTO)
fsm_driver(&fsm21);
问题
- 监视位置和结果相同的位置 三个集合(组织思路:事件为单位 且单一 读写 其他的都为异常) 读写集合,异常集合 ;出了假错 要重新布置现场
- int nfds 溢出 大小限制 不超过 有符号数整形大小