• 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模型

    2.1 阻塞IO

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

     

    2.2 非阻塞I/O

    示例

    read

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define FIFO_NAME "/tmp/myfifo"
    9. int main(int argc, char *argv[]) {
    10. int fd, ret;
    11. char buf[BUFSIZ] = {};
    12. // 创建有名管道
    13. if (mkfifo(FIFO_NAME, 0666) == -1) {
    14. perror("mkfifo");
    15. exit(0);
    16. }
    17. fd = open(FIFO_NAME, O_RDONLY|O_NONBLOCK); //非阻塞方式NONBLOCK
    18. if(fd < 0) {
    19. perror("open");
    20. exit(0);
    21. }
    22. while(1) {
    23. // do {
    24. ret = read(fd, buf, BUFSIZ);
    25. // } while (ret < 0 && errno == EAGAIN); //如果读失败了,并且原因是EAGAIN才会反复轮询读
    26. // if(ret < 0){ //如果满足EGAIN但是,但是RET<0,是其他异常情况
    27. // perror("read");
    28. // exit(0);
    29. // }
    30. if(buf[0] == '#')
    31. break;
    32. printf("Read from pipe: %s\n", buf);
    33. }
    34. // 关闭管道并删除有名管道文件
    35. close(fd);
    36. unlink(FIFO_NAME);
    37. return 0;
    38. }

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

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

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

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

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define FIFO_NAME "/tmp/myfifo"
    8. int main(void) {
    9. int fd;
    10. char buf[BUFSIZ];
    11. // 打开有名管道并进行读写操作
    12. fd = open(FIFO_NAME, O_WRONLY);
    13. if( fd < 0 ) {
    14. perror("open");
    15. exit(0);
    16. }
    17. while(1) {
    18. fgets(buf, BUFSIZ, stdin);
    19. if (write(fd, buf, BUFSIZ) < 0 ) {
    20. perror("write");
    21. exit(0);
    22. }
    23. if(buf[0] == '#')
    24. break;
    25. }
    26. close(fd);
    27. return 0;
    28. }

     2.3 多路复用I/O

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

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

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

     2.4 信号驱动式I/O

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

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

    2.5 异步I/O模型

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

    3 五种I/O模型比较

    4 练习

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

  • 相关阅读:
    nginx日志进行统计分析 log分析
    微信小程序能不能有一种公共的分包,能被普通的分包引用其资源?(内有解决方案)
    c++:三种实例化对象方式
    Android 10.0 Camera2退出时屏幕旋转为横屏
    指针函数、函数指针、指针函数数组
    八大排序算法----堆排序
    SpringBoot轻松实现项目集成Knife4j接口文档
    手写raft(二) 实现日志复制
    java计算机毕业设计幼儿早教系统软件设计与实现MyBatis+系统+LW文档+源码+调试部署
    五金机电行业经销商协同管理系统解决方案
  • 原文地址:https://blog.csdn.net/m0_60718520/article/details/133617599