Programming principles and programming examples of finite state machines

Finite State Machine

The problems that finite state machines solve are complex processes.
Simple Processes: Natural processes are structured, sequential human thinking to solve problems.
Complex flow: Natural flow is not structured, like the previous MultiButton.

specific examples

Under the Linux operating system, the terminal device interface can be switched between each other. Realize that the data read from fd1 is written to fd2, and the data read from fd2 is written to fd1.

A simple schematic diagram of the state machine is shown below:
insert image description here

Experimental project source code

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.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;
    /*读取长度*/
    int len;
    /*位置*/
    int pos;
    /*报错信息*/
    char * errstr;
    /*buf缓冲区*/
    char buf[BUFSIZE];
};


/***********************启动状态机*****************/
static void fsm_driver(struct fsm_st*fsm)
{
    
    
    int ret;
    
    switch (fsm->state)
    {
    
    
    /*状态机读取*/
    case STATE_R:
    	/*读取到的源fd存储到buf中*/
        fsm->len = read(fsm->sfd,fsm->buf,BUFSIZE);
        /*如果读取0字节,退出状态机*/
        if (fsm->len == 0)
        fsm->state = STATE_T;
        /*如果读取<0字节,进行状态判断*/
        else if (fsm->len < 0)
        {
    
    
           /*如果读取<0字节,二次判断*/
            if (errno == EAGAIN)
                fsm->state =STATE_R;
            else
            {
    
    
            	/*宕机退出*/
                fsm->errstr = "read()";
                fsm->state =STATE_Ex;
            }    
        }
        else
        /*都没有报错,说明读取正常,则开始状态机写入*/
        {
    
    
        /*******初始化写入的位置为0***************/
            fsm->pos = 0;
            fsm->state =STATE_W;     
        }  
        break;
        
   /*状态机写入*/
    case STATE_W:
        /*写入读取到的数据len*/
        ret = write(fsm->dfd,fsm->buf+fsm->pos,fsm->len);
		/*写入读取到的数据<0*/
        if(ret < 0)
        {
    
    
        	/*假的错误*/
            if (errno == EAGAIN)
            	/*再次进入写入*/
                fsm->state = STATE_W;
            else 
            /*真正读取错误*/
            {
    
    
            	/*读取错误*/
                fsm->errstr = "read()";
                /*宕机退出*/
                fsm->state =STATE_Ex;
            }      
        }
        else
      /***************坚持写够len个字节数***************/
        {
    
    
           /*******从pos的位置继续向下写入字节***************/
            fsm->pos += ret;
            fsm->len -= ret;
            /*如果写入完成*/
            if(fsm->len == 0)
                /*返回读态*/
                fsm->state = STATE_R;
            /*否则返回写态,继续写够len个字节*/
            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();
        break;
    }

}
 
 
static void relay(int fd1,int fd2)
{
    
    
    int fd1_save,fd2_save;
    /*读左写右和读右写左状态机*/
    struct fsm_st fsm12,fsm21;
    /***********************************************/
    /*保证两个文件是以非阻塞方式实现*/
    /*fcntl函数的作用是获取文件状态信息*/
    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 )
    {
    
    
        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);
    if (fd2<0)
    {
    
    
        perror("open()");
        exit(1);
    }

    write(fd2,"TTY2\n",5);
	/*中继引擎函数*/
    relay(fd1,fd2);
    close(fd2);
    close(fd1);
    
    exit(0);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324131429&siteId=291194637