七.高级IO

非阻塞IO – 阻塞IO
补充:有限状态机编程
1 非阻塞IO

简单流程:自然流程是结构化的
复杂流程:自然流程不是结构化的

2 IO多路转接

select()
poll()
epoll()
select和poll可移植,epoll不可移植(linux自己的)

3 其他读写函数
4 存储映射IO
5 文件锁

1.数据中继——用有限状态机解决

阻塞IO、非阻塞IO、多路复用IO、信号驱动IO以及异步IO

浅谈I/O模型

两个设备交换数据:
法1:读1->写2->读2->写1 阻塞的形式,容易一直卡在某一步
法2:读1->写2 和 读2->写1 分开 非阻塞的形式更好

1.非阻塞假错 EAGAIN: The file descriptor fd refers to a file other than a socket and has been marked nonblocking (O_NONBLOCK), and the read would block. See open(2) for further details on the O_NONBLOCK flag.(读取不到直接返回,不是真正错误)
2.阻塞假错 EINTR: While blocked waiting to complete an open of a slow device (e.g., a FIFO; see fifo(7)), the call was interrupted by a signal handler; see signal(7).

代码的状态转移图:
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include<errno.h>



#define     TTY1       "/dev/tty11"
#define     TTY2       "/dev/tty12"
#define     BUFSIZE     1024
enum {
	//几种状态
	STATE_R,
	STATE_W,
	STATE_EX,
	STATE_T	
};

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


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;
		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 relay(int fd1, int fd2) {
	struct fsm_st fsm12,fsm21;
	int fd1_save = fcntl(fd1, F_GETFL);
	fcntl(fd1, F_SETFL, fd1_save|O_NONBLOCK);  //非阻塞	打开


	int 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 argc, char** argv) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
	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);		//核心代码
	exit(0);

}

2.中继引擎实例

IO密集型任务
在上面的基础上,实现最多10000对设备两两通信互不干扰

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

3.高级IO-select

函数:

select:
参数:文件描述符中大的那个+1, 读文件描述符集,写集,异常集,超时设置
RETURN VALUE
On success, select() and pselect() return the number of file descriptors contained in the three returned descriptor sets (that is, the total number of bits that are set in readfds, writefds, exceptfds) which may be zero if the timeout expires before anything interesting happens. On error, -1 is returned, and errno is set
to indicate the error; the file descriptor sets are unmodified, and timeout becomes undefined.
在这里插入图片描述
FD_CLR是fd_set中删除fd文件描述符
FD_ISSET是判断fd在不在集合
FD_SET是添加fd进集合
FD_ZERO是清空集合

select存在的问题:
1.布置感兴趣事件和事件返回存放在同一块内存(3个集),每次报假错(EAGAIN)后都得绕大圈重新布置现场。
2.文件描述符数量限制(INT_MAX)
3.事件单一,只有读,写,异常

基于第一节数据中继的改进

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include<errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>


#define     TTY1       "/dev/tty11"
#define     TTY2       "/dev/tty12"
#define     BUFSIZE     1024
enum {
	//几种状态
	STATE_R,
	STATE_W,
	STATE_AUTO,
	STATE_EX,
	STATE_T
};

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


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;
		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 int max(int a, int b) {
	return a > b ? a : b;
}
static void relay(int fd1, int fd2) {
	struct fsm_st fsm12, fsm21;
	fd_set rset, wset;//读集,写集
	int fd1_save = fcntl(fd1, F_GETFL);
	fcntl(fd1, F_SETFL, fd1_save | O_NONBLOCK);  //非阻塞 打开


	int 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) {
		//布置监视任务

		FD_ZERO(&rset);
		FD_ZERO(&wset);
		if (fsm12.state == STATE_R)
			FD_SET(fsm12.sfd, &rset);
		if (fsm12.state == STATE_W)
			FD_SET(fsm12.dfd, &wset);
		if (fsm21.state == STATE_R)
			FD_SET(fsm21.sfd, &rset);
		if (fsm21.state == STATE_W)
			FD_SET(fsm21.dfd, &wset);
		//监视
		if (fsm12.state < STATE_AUTO || fsm21.state < STATE_AUTO) {					//只有在读写状态的才select
			if (select(max(fd1, fd2) + 1, &rset, &wset, NULL, NULL) < 0) {
				if (errno == EINTR) {
					continue;
				}
				perror("select()");
				exit(1);
			}
		}
		
		//查看监视结果
		if (FD_ISSET(fd1, &rset) || FD_ISSET(fd2, &wset) || fsm12.state > STATE_AUTO)//如果1可读2可写或者处于EX,T态
			fsm_driver(&fsm12);
		if (FD_ISSET(fd2, &rset) || FD_ISSET(fd1, &wset) || fsm21.state > STATE_AUTO)//如果2可读1可写
			fsm_driver(&fsm21);
	}

	//复原退出
	fcntl(fd1, F_SETFL, fd1_save);
	fcntl(fd2, F_SETFL, fd2_save);
}

int main(int argc, char** argv) {
	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);		//核心代码
	exit(0);

}

4.poll实例

select是以事件为单位组织文件描述符,poll是以文件描述符为单位组织事件
在这里插入图片描述
参数1:结构体pollfd数组首地址,可以看到结构体中感兴趣事件和储存结果事件是分开的,解决了select函数的第一个缺陷
参数2:结构体数组的长度
参数3:以毫秒为单位,0表示非阻塞,-1表示阻塞死等

还可以看到poll可以表示的events数量大于2

在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include<errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <poll.h>

#define     TTY1       "/dev/tty11"
#define     TTY2       "/dev/tty12"
#define     BUFSIZE     1024
enum {
	//几种状态
	STATE_R,
	STATE_W,
	STATE_AUTO,
	STATE_EX,
	STATE_T
};

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


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;
		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 int max(int a, int b) {
	return a > b ? a : b;
}
static void relay(int fd1, int fd2) {
	struct fsm_st fsm12, fsm21;
	struct pollfd pfd[2];
	int fd1_save = fcntl(fd1, F_GETFL);
	fcntl(fd1, F_SETFL, fd1_save | O_NONBLOCK);		//非阻塞	打开


	int 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;



	pfd[0].fd = fd1;
	pfd[1].fd = fd2;
	while (fsm12.state != STATE_T || fsm21.state != STATE_T) {

		//布置监视任务
		pfd[0].events = 0;//位图清0
		if (fsm12.state == STATE_R)   //如果可读,或上读的事件
			pfd[0].events |= POLLIN;
		if (fsm21.state == STATE_W)
			pfd[0].events |= POLLOUT;

		pfd[1].events = 0;
		if (fsm12.state == STATE_W)
			pfd[1].events |= POLLOUT;
		if (fsm21.state == STATE_R)
			pfd[1].events |= POLLIN;
		
		//监视
		if (fsm12.state < STATE_AUTO || fsm21.state < STATE_AUTO) {					
			while (poll(pfd, 2, -1) < 0){			 //pollfd数组首地址, 数组长度, 阻塞形式
				if (errno == EINTR) {
					continue;
				}
				perror("poll()");
				exit(1);
			}
		}
		
		//查看监视结果
		if ( pfd[0].revents & POLLIN || pfd[1].revents & POLLOUT || fsm12.state > STATE_AUTO)//如果1可读2可写或者处于EX,T态
			fsm_driver(&fsm12);
		if (pfd[1].revents & POLLIN || pfd[0].revents & POLLOUT || fsm21.state > STATE_AUTO)//如果2可读1可写
			fsm_driver(&fsm21);
	}

	//复原退出
	fcntl(fd1, F_SETFL, fd1_save);
	fcntl(fd2, F_SETFL, fd2_save);
}

int main(int argc, char** argv) {
	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);		//核心代码
	exit(0);

}



5.epoll实例

函数:

int epoll_create(int size)
the size argument is ignored, but must be greater than zero

RETURN VALUE
On success, these system calls return a nonnegative file descriptor. On error, -1 is returned, and errno is set to indicate the error.

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
This system call performs control operations on the epoll(7) instance referred to by the file descriptor epfd. It requests that the operation op be performed for the target
file descriptor, fd.
RETURN VALUE
When successful, epoll_ctl() returns zero. When an error occurs, epoll_ctl() returns -1 and errno is set appropriately.

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
DESCRIPTION
The epoll_wait() system call waits for events on the epoll(7) instance referred to by the file descriptor epfd. The memory area pointed to by events will contain the events
that will be available for the caller. Up to maxevents are returned by epoll_wait(). The maxevents argument must be greater than zero.
timeout=0是非阻塞,-1是阻塞死等

epoll_ctl中的参数:
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include<errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/epoll.h>

#define     TTY1       "/dev/tty11"
#define     TTY2       "/dev/tty12"
#define     BUFSIZE     1024
enum {
	//几种状态
	STATE_R,
	STATE_W,
	STATE_AUTO,
	STATE_EX,
	STATE_T
};

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


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;
		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 int max(int a, int b) {
	return a > b ? a : b;
}
static void relay(int fd1, int fd2) {
	struct fsm_st fsm12, fsm21;
	int epfd;
	struct epoll_event ev;
	int fd1_save = fcntl(fd1, F_GETFL);
	fcntl(fd1, F_SETFL, fd1_save | O_NONBLOCK);		//非阻塞	打开


	int 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;

	epfd = epoll_create(1);
	if (epfd < 0) {
		perror("epoll_create()");
		exit(1);
	}
	ev.events = 0;
	ev.data.fd = fd1;
	epoll_ctl(epfd, EPOLL_CTL_ADD, fd1, &ev);

	ev.events = 0;
	ev.data.fd = fd2;
	epoll_ctl(epfd, EPOLL_CTL_ADD, fd2, &ev);
	while (fsm12.state != STATE_T || fsm21.state != STATE_T) {

		//布置监视任务
		ev.data.fd = fd1;
		ev.events = 0;//位图清0


		if (fsm12.state == STATE_R)   //如果可读
			ev.events |= EPOLLIN;
		if (fsm21.state == STATE_W)
			ev.events |= EPOLLOUT;

		epoll_ctl(epfd, EPOLL_CTL_MOD, fd1, &ev);

		ev.data.fd = fd2;
		ev.events = 0;//位图清0
		if (fsm12.state == STATE_W)
			ev.events |= EPOLLOUT;
		if (fsm21.state == STATE_R)
			ev.events |= EPOLLIN;

		//监视
		if (fsm12.state < STATE_AUTO || fsm21.state < STATE_AUTO) {					
			while (epoll_wait(epfd, &ev, 1, -1) < 0) {			 //
				if (errno == EINTR) {
					continue;
				}
				perror("epoll_wait()");
				exit(1);
			}
		}

		//查看监视结果
		if (ev.data.fd == fd1 && ev.events & EPOLLIN || ev.data.fd == fd2 \
			&& ev.events & EPOLLOUT || fsm12.state > STATE_AUTO)//如果1可读2可写或者处于EX,T态
			fsm_driver(&fsm12);
		if (ev.data.fd == fd1 && ev.events & EPOLLOUT || ev.data.fd == fd2 \
			&& ev.events & EPOLLIN || fsm21.state > STATE_AUTO)//如果2可读1可写
			fsm_driver(&fsm21);
	}

	//复原退出
	fcntl(fd1, F_SETFL, fd1_save);
	fcntl(fd2, F_SETFL, fd2_save);

	close(epfd);
}

int main(int argc, char** argv) {
	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);		//核心代码
	exit(0);

}



6.内存映射

函数readv, writev
mmap()

在这里插入图片描述
在这里插入图片描述
函数mmap(), munmap()

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值