使用状态有限机实现数据中继

**有限状态机:**解决复杂流程问题
简单流程:如果一个程序自然流程是结构化的(无分支)
复杂流程:如果一个程序自然流程是非结构化的(有分支)
实现数据交互:
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返回图形界面
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值