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假错(等待一端读或者写)