lv8 嵌入式开发-网络编程开发 14

目录

1 I/O基本概念

1.1 IO概念

1.2 同步和异步

1.3 阻塞和非阻塞

2 五种I/O模型

2.1 阻塞IO

2.2 非阻塞I/O

 2.3 多路复用I/O

​编辑 2.4 信号驱动式I/O

​编辑

2.5 异步I/O模型​编辑

3 五种I/O模型比较

4 练习


1 I/O基本概念

1.1 IO概念

  • I/O即数据的读取(接收)或写入(发送)操作
  • 通常用户进程中的一个完整I/O分为两个阶段

        用户进程空间<-->内核空间

        内核空间<-->设备空间(磁盘、网卡等)

  • I/O分为内存I/O、网络I/O和磁盘I/O三种

1.2 同步和异步

  • 对于一个线程的请求调用来讲,同步和异步的区别在于是否要等这个请求出最终结果
  • 对于多个线程而言,同步或异步就是线程间的步调是否要一致、是否要协调
  • 同步也经常用在一个线程内先后两个函数的调用上
  • 异步就是一个请求返回时一定不知道结果,还得通过其他机制来获知结果,如:主动轮询或被动通知

1.3 阻塞和非阻塞

  • 阻塞与非阻塞与等待消息通知时的状态(调用线程)有关
  • 阻塞和同步是完全不同的概念。同步是对于消息的通知机制而言,阻塞是针对等待消息通知时的状态来说的
  • 进程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态

线程在运行过程中,可能由于以下几种原因进入阻塞状态:

  • 线程通过调用sleep方式进休眠状态
  • 线程调用一个在I/O上被阻塞的操作,即该操作在输入/输出操作完成前不会返回到它的调用者
  • 线程试图得到一个锁,而该锁正被其他线程持有,于是只能进入阻塞状态,等到获取了同步锁,才能恢复执行
  • 线程在等待某个触发条件

可能阻塞套接字的Linux Sockets API调用分为以下四种

  • 输入操作
  • 输出操作
  • 接受连接accept
  • 外出连接connect

2 五种I/O模型

lv8 嵌入式开发-网络编程开发 14_第1张图片

2.1 阻塞IO

内核也有数据缓存区,数据好了再拷贝到应用的缓存区中,包括read,accept、connect等 

lv8 嵌入式开发-网络编程开发 14_第2张图片

 

lv8 嵌入式开发-网络编程开发 14_第3张图片

2.2 非阻塞I/O

示例

read

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define FIFO_NAME "/tmp/myfifo"

int main(int argc, char *argv[]) {
    int fd, ret;
    char buf[BUFSIZ] = {};

    // 创建有名管道
    if (mkfifo(FIFO_NAME, 0666) == -1) {
        perror("mkfifo");
		exit(0);
    }

    fd = open(FIFO_NAME, O_RDONLY|O_NONBLOCK);  //非阻塞方式NONBLOCK
	if(fd < 0) {
		perror("open");
		exit(0);
	}

	while(1) {
	//	do {
			ret = read(fd, buf, BUFSIZ); 
	//	} while (ret < 0 && errno == EAGAIN);   //如果读失败了,并且原因是EAGAIN才会反复轮询读
	//	if(ret < 0){                 //如果满足EGAIN但是,但是RET<0,是其他异常情况
	//		perror("read");
	//		exit(0);
	//	}
		if(buf[0] == '#')
			break;
		printf("Read from pipe: %s\n", buf);
	}

    // 关闭管道并删除有名管道文件
    close(fd);
	unlink(FIFO_NAME);

    return 0;
}

 该程序通过使用read函数从文件描述符fd中读取数据,存储在buf中。BUFSIZ是一个常量,表示可以读取的最大字节数。当读取成功时,read函数返回实际读取的字节数,如果返回值小于0,则表示读取出现错误。

程序使用循环来反复读取数据,直到遇到以#开头的字符串,才会跳出循环。在读取过程中,如果读取失败了,并且原因是EAGAIN,则会一直轮询读取,直到成功读取为止。

注释掉的部分是对异常情况的处理,如果出现其他异常情况,则会输出错误信息并退出程序。

write函数仅用来测试,无特别说明

#include 
#include 
#include 
#include 
#include 
#include 

#define FIFO_NAME "/tmp/myfifo"

int main(void) {
    int fd;
    char buf[BUFSIZ];

    // 打开有名管道并进行读写操作
    fd = open(FIFO_NAME, O_WRONLY);
	if( fd < 0 ) {
		perror("open");
		exit(0);
	}
	while(1) {
		fgets(buf, BUFSIZ, stdin);
		if (write(fd, buf, BUFSIZ) < 0 ) {
			perror("write");
			exit(0);
		}
		if(buf[0] == '#')
			break;
	}

    close(fd);
    return 0;
}

 2.3 多路复用I/O

与read区别,可以监听多个文件描述符,有的可能有数据,有的可能没有数据。

如果有数据准备好的描述符,返回可读条件,如哪个文件描述符好了。

如果有数据了,调用recvfrom拷贝数据报,再进行处理。如果有多个文件描述符就执行多个这样的过程。

lv8 嵌入式开发-网络编程开发 14_第4张图片 2.4 信号驱动式I/O

注册完就可以干别的事情了,类似异步操作。

lv8 嵌入式开发-网络编程开发 14_第5张图片

上面4种,在数据报准备好之后拷贝数据的时候都是阻塞的,都算作是同步IO,都需要recv读一下。

2.5 异步I/O模型lv8 嵌入式开发-网络编程开发 14_第6张图片

内核无数据到数据报拷贝完成,这两部都是非阻塞的,应用程序干干什么就干什么。

3 五种I/O模型比较

lv8 嵌入式开发-网络编程开发 14_第7张图片

4 练习

画出5种I/O模型调用过程 

你可能感兴趣的:(嵌入式开发,网络,linux)