**有限状态机:**解决复杂流程问题
简单流程:如果一个程序自然流程是结构化的(无分支)
复杂流程:如果一个程序自然流程是非结构化的(有分支)
实现数据交互:
1.读左-写右-写右-读左 (阻塞)
2.读左-写右
读右-写左(非阻塞)
有限状态机步骤:
1.确定状态机初始状态和终止状态
2.确定状态机的结构体内容
3.画流程图,编写状态机驱动函数
使用状态有限机实现两个终端TTY1 和TTY2的数据中继(cocy):
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include <unistd.h>
#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define BUFSIZE 1024
//需要两个状态机实现copy
enum
{
STATE_R=1,
STATE_W,
STATE_Ex,//异常态
STATE_T//退出态
};/*状态机状态*/
struct fsm_st/*状态机结构体*/
{
int state;
int sfd;//source fd
int dfd;//destination fd
char buf[BUFSIZE];
int len;//读的长度
char *errstr;
int pos;//读到的位置
};
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;
//接收的数据为0 转为终止态
else if(fsm->len<0)
{
if(errno==EAGAIN)
fsm->state=STATE_R;
else
{fsm->state=STATE_Ex;//异常态
fsm->errstr="读出错";
}
}
else { fsm->pos=0;
fsm->state=STATE_W;}
break;
case STATE_W:
ret=write(fsm->dfd,fsm->buf+fsm->pos,fsm->len);
if(ret<0)
{
if(errno==EAGAIN)
fsm->state=STATE_W;
else
{fsm->state=STATE_Ex;//异常态
fsm->errstr="写出错";
}
}
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:
abort();//人为异常 得到core dump
break;
}
}
static void relay(int fd1,int fd2)
{
int fd1_save=fcntl(fd1,F_GETFL);
/*
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
cmd: F_GETFL 取得文件描述符状态旗标,此旗标为open()的参数flags。
F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。
*/
fcntl(fd1,F_SETFL,fd1_save|O_NONBLOCK);
//文件原有属性增加o_nonblock非阻塞
int fd2_save=fcntl(fd2,F_GETFL);
fcntl(fd2,F_SETFL,fd2_save|O_NONBLOCK);
struct fsm_st fsm12,fsm21;//12读左写右 21读右写左
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)//当状态机未终止时
{
fsm_driver(&fsm12);
fsm_driver(&fsm21);//推动状态机
}
fcntl(fd1,F_SETFL,fd1_save);//恢复之前的状态
fcntl(fd2,F_SETFL,fd2_save);
}
int main()
{
int fd1,fd2;
fd1=open(TTY1,O_RDWR);
if(fd1<0)
{
perror("open()");
exit(1);
}
write(fd1,"TTY1\n",5);
fd2=open(TTY2,O_RDWR|O_NONBLOCK);
//o_nonblock 设置为非阻塞方式
//之后调用read不会阻塞住
if(fd2<0)
{
perror("open()");exit(1);
}
write(fd2,"TTY2\n",5);
relay(fd1,fd2);
close(fd2);
close(fd1);
exit(0);
}
root用户使用ctrl+alt+f11和ctrl+alt+f12查看两个终端的输入输入信息 ctrl+alt+f4返回图形界面