有限状态机编程

1.概念

有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

2.数据中继

终端1向终端2发送数据,然后终端2进行处理后,在发送回终端1
也就是一个myCpy的重构
在这里插入图片描述

3.代码

#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define BUFSIZE 20

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 *ErrString;
};


void fsm_driver(struct fsm_st *p)
{
    
    
        int Len;

        switch(p->State)
        {
    
    
          case STATE_R:
                p->Len = read(p->sfd, p->Buf, BUFSIZE);
                if(0 == p->Len)//已经读取完成全部
                        p->State = STATE_T;
                else if(p->Len < 0)
                {
    
    
                        if(EAGAIN == errno)//假错
                                p->State = STATE_R;
                        else//真错
                        {
    
    
                                p->State = STATE_EX;
                                p->ErrString = "Read Err";
                        }
                }
                else//读取成功
                {
    
    
                        p->Pos = 0;
                        p->State = STATE_W;
                }
                break;
          case STATE_W:
                Len = write(p->dfd, p->Buf + p->Pos, p->Len);
                if(Len < 0)
                {
    
    
                        if(EAGAIN == errno)//假错
                                p->State = STATE_W;
                        else//真错
                        {
    
    
                                p->State = STATE_EX;
                                p->ErrString = "Write Err";
                        }

                }
                else
                {
    
    
                        p->Pos += Len;
                        p->Len -= Len;
                        if(0 == p->Len)//写入完成
                                p->State = STATE_R;
                        else    //如果没有写够 
                                p->State = STATE_W;
                }

                break;
          case STATE_EX:
                perror(p->ErrString);
                p->State = STATE_T;

                break;
          case STATE_T:
                // Do Something
                break;
          default:
                abort();
                break;

        }
}


void relay(int fd1, int fd2)
{
    
    
        int fd1_save;
        int fd2_save;
        struct fsm_st fsm12, fsm21;

        //不能确定哪个是阻塞哪个是非阻塞
        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(STATE_T == fsm12.State || STATE_T == fsm21.State)
        {
    
    
                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);
        }

        fd2 = open(TTY2, O_RDWR|O_NONBLOCK);
        if(fd2 < 0)
        {
    
    
                perror("open()");
                exit(1);
        }


        close(fd2);
        close(fd1);

        return 0; 
}

4.中继引擎实例

relayer.h

#ifndef RELAYER_H__
#define RELAYER_H__

#include <stdint.h>
#define   REL_JOBMAX  10000
enum {
    
    
	STATE_RUNNING = 1,
	STATE_CANCELED,
	STATE_OVER
};
struct rel_stat_st {
    
    
	int state;
	int fd1;
	int fd2;
	int64_t count12, count21;//1向2发送了多少字节,2向1发送了多少字节
};


int rel_addjob(int fd1, int fd2);
/*
	return >= 0			成功,返回当前任务ID
		   == -EINVAL	失败,参数非法
		   == -ENOSPC   失败,任务数组满
		   == -ENOMEM   失败,内存分配有误
*/



int rel_canceljob(int id);
/*
	return == 0			成功,指定任务成功取消
		   == -EINVAL	失败,参数非法
		   == -EBUSY    失败,任务早已被取消
*/



int rel_waitjob(int id, struct rel_stat_st*);
/*
	return == 0			成功,指定任务已终止并返回状态
		   == -EINVAL	失败,参数非法
		
*/



int rel_statjob(int id, struct rel_stat_st*);
/*

	return == 0			成功,指定任务状态返回
		   == -EINVAL	失败,参数非法

*/
#endif


relayer.c

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<pthread.h>
#include <unistd.h>
#include"relayer.h"
#include<string.h>
#include<fcntl.h>



static struct rel_job_st* rel_job[REL_JOBMAX];
static pthread_mutex_t mut_rel_job = PTHREAD_MUTEX_INITIALIZER;
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
enum {
    
    
	//几种状态
	STATE_R,
	STATE_W,
	STATE_EX,
	STATE_T
};

#define   BUFSIZE  1024


//状态机
struct rel_fsm_st {
    
    
	int state;//记录状态
	int sfd;//源文件
	int dfd;//目的文件
	char buf[BUFSIZE];//中间缓冲区
	int len;//读到的长度
	int pos;//写的过程如果一次没有写完,记录上次写的位置
	char* err;//错误信息
	int64_t count;
};


//每一对终端结构体
struct rel_job_st{
    
    
	//两个终端
	int fd1;
	int fd2;
	//该对终端状态STATE_RUNNING,STATE_CANCELED, STATE_OVER
	int job_state;
	//两个终端的状态机结构体
	struct rel_fsm_st fsm12, fsm21;
	//用来退出复原状态
	int fd1_save, fd2_save;

};

//状态转移函数
static void fsm_driver(struct rel_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->err = "read()";
				fsm->state = STATE_EX;
			}

		}
		else {
    
    
			fsm->pos = 0;
			fsm->state = STATE_W;
		}

		break;
	case STATE_W:
		ret = write(fsm->dfd, fsm->buf + fsm->pos, BUFSIZE);
		if (ret < 0) {
    
    
			if (errno == EAGAIN)
				fsm->state = STATE_W;
			else {
    
    
				fsm->err = "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->err);
		fsm->state = STATE_T;
		break;
	case STATE_T:
		/*  do smoething*/
		break;
	default:
		abort();
		break;

	}
}


static void* thr_relayer(void *p) {
    
    
	int i;
	while (1) {
    
    
		pthread_mutex_lock(&mut_rel_job);
		for (i = 0; i < REL_JOBMAX; i++) {
    
    
			if (rel_job[i] != NULL) {
    
    
				if (rel_job[i]->job_state == STATE_RUNNING) {
    
    
					fsm_driver(&rel_job[i]->fsm12);
					fsm_driver(&rel_job[i]->fsm21);
					if (rel_job[i]->fsm12.state == STATE_T && rel_job[i]->fsm21.state == STATE_T)
						rel_job[i]->job_state = STATE_OVER;
				}
			}
		}
		pthread_mutex_unlock(&mut_rel_job);
	}
	
}

static void module_load(void) {
    
    
	int err;
	pthread_t tid_relayer;
	err = pthread_create(&tid_relayer, NULL, thr_relayer, NULL);
	if (err) {
    
    
		fprintf(stderr, "pthread_create():%s\n", strerror(err));
		exit(1);
	}

}

static int get_free_pos_unlocked() {
    
    
	int i;
	for (i = 0; i < REL_JOBMAX; i++) {
    
    
		if (rel_job[i] == NULL)
			return i;
	}
	return -1;
}

int rel_addjob(int fd1, int fd2) {
    
    
	struct rel_job_st *me;
	int pos;

	pthread_once(&init_once, module_load);
	me = malloc(sizeof(*me));
	if (me == NULL)   //空间问题
		return -ENOMEM;
	me->fd1 = fd1;
	me->fd2 = fd2;
	me->job_state = STATE_RUNNING;//该对终端设置正在运行

	me->fd1_save = fcntl(me->fd1, F_GETFL);
	fcntl(me->fd1, F_SETFL, me->fd1_save | O_NONBLOCK);  //非阻塞	打开

	me->fd2_save = fcntl(me->fd2, F_GETFL);
	fcntl(me->fd2, F_SETFL, me->fd2_save | O_NONBLOCK);//非阻塞	打开

	me->fsm12.sfd = me->fd1;
	me->fsm12.dfd = me->fd2;
	me->fsm12.state = STATE_R;

	me->fsm21.sfd = me->fd2;
	me->fsm21.dfd = me->fd1;
	me->fsm21.state = STATE_R;

	pthread_mutex_lock(&mut_rel_job);
	pos = get_free_pos_unlocked();
	if (pos < 0) {
    
    
		pthread_mutex_unlock(&mut_rel_job);
		fcntl(me->fd1, F_SETFL, me->fd1_save);
		fcntl(me->fd2, F_SETFL, me->fd2_save);
		free(me);
		return -ENOSPC;
	}
	rel_job[pos] = me;
	pthread_mutex_unlock(&mut_rel_job);
	return pos;

}


int rel_canceljob(int id);
/*
	return == 0			成功,指定任务成功取消
		   == -EINVAL	失败,参数非法
		   == -EBUSY    失败,任务早已被取消
*/



int rel_waitjob(int id, struct rel_stat_st*);




int rel_statjob(int id, struct rel_stat_st*);

main.c

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include<errno.h>
#include<string.h>
#include"relayer.h"


//两个设备为一对互传数据
#define     TTY1       "/dev/tty11"
#define     TTY2       "/dev/tty12"


#define     TTY3       "/dev/tty10"
#define     TTY4       "/dev/tty9"


int main(int argc, char** argv) {
    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
	int fd1, fd2, fd3, fd4;
	int job1, job2;
	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);

	job1 = rel_addjob(fd1, fd2);//添加一对终端互传数据  
	if (job1 < 0) {
    
    
		fprintf(stderr, "rel_addjob():%s\n", strerror(-job1));
		exit(1);
	}
	


	fd3 = open(TTY3, O_RDWR);//先以阻塞打开(故意先阻塞形式)
	if (fd3 < 0) {
    
    
		perror("open()");
		exit(1);
	}
	write(fd3, "TTY3\n", 5);
	fd4 = open(TTY4, O_RDWR | O_NONBLOCK);//非阻塞
	if (fd4 < 0) {
    
    
		perror("open()");
		exit(1);
	}
	write(fd4, "TTY4\n", 5);

	job2 = rel_addjob(fd3, fd4);//添加一对终端互传数据  
	if (job2 < 0) {
    
    
		fprintf(stderr, "rel_addjob():%s\n", strerror(-job2));
		exit(1);
	}

	while (1)
		pause();

	close(fd4);
	close(fd3);
	close(fd2);
	close(fd1);
	
	exit(0);

}

这段代码的问题主要是一直占用着cpu, 一直报EAGAIN假错(等待一端读或者写)

猜你喜欢

转载自blog.csdn.net/ZZHinclude/article/details/119789169