1、IO分类

  1. 阻塞IO:
    在进行IO操作的时候,如果资源没有准备就绪,会阻塞等待资源,如果资源准备就绪,获取资源。 常用、简单、效率很低
  2. 非阻塞IO:
    在进行IO操作的时候,如果资源没有准备就绪,返回错误信息,如果资源就绪,获取资源。 任务不会阻塞、轮询访问,CPU的消耗较大。
  3. IO多路复用:
    将所有操作的IO放到一个集合中,检测集合中准备就绪的IO,然后进行IO操作。 允许同时对多个IO进行操作。
  4. 信号驱动IO:
    资源准备就绪的时候,由内核向任务发送SIGIO信号,任务接收到信号后,去进行IO操作。

2、阻塞IO

资源没有准备就绪,会一直等待
常用的有fgets、read、write、accept......

3、非阻塞IO

应用程序在执行的时候告诉系统,如果资源准备就绪,返回资源,如果没有准备就绪,返回错误信息。 实现方式更多采用轮询(polling)
具体实现步骤:
1) 需要将IO设置为非阻塞模式;
    a, 打开的时候以非阻塞方式去得到;
        open(pathname, O_NONBLOCK | O_RDWR);
    b,在得到IO的文件描述符后,可以去设置。
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
参数:
参数1:fd表示文件描述符
参数2:int cmd, ... /* arg */ 是可变参数,
返回值:
成功:
F_GETFL Value of file status flags.
F_SETFL 0;
失败返回-1,且修改errno的值。

4、IO多路复用

如果现在我来同时操作多个IO:
1) 采用阻塞模式,IO的操作顺序由代码决定,多个IO是依次执行; 只要前面的IO没有执行,后面的IO即使资源准备就绪,也不会执行。达不到预期效果(谁准备就绪就执行谁);
2) 非阻塞IO模式,多个IO需要进行轮询访问,导致CPU的消耗很大。不利于执行其它任务。
3) 采用多任务的方式: 多进程,每一个任务创建一个进程,这个进程会有独立4g内存空间,通信比较麻烦。 多线程,资源共享,需要解决资源互斥和线程的同步。
IO多路复用的思路:
1) 先创建一个文件描述符集合,将所要关心事件的描述符添加到集合中;
2) 调用函数来检测集合,检测是否有准备就绪的事件,有事件准备就绪函数返回,没有事件准备就绪函数阻塞
3) 得到准备就绪事件的文件描述符
4) 对准备就绪的文件描述符进行IO操作。
具体实现机制:
1. select机制:
    将关注的IO操作放到一个集合中,通过select函数实现阻塞遍历,当关注的文件描述符有对应的资源准备就绪,select函数就会返回,返回值代表资源准备就绪的个数,所以需要通过循环遍历判断是哪一种资源准备就绪。select函数每次检测都是从0~1023遍历。集合总共128字节。
编程流程:
    1、创建集合
    2、清空集合
    3、将关注的文件描述符逐个加入集合
    4、select经数阻塞检测资源是否就绪
    5、循环遍历检测对应的资源
    6、做对应资源相关的操作
    7、回到第4步(用一个while循环)
1) 函数接口:
/* According to POSIX.1-2001 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数:
    参数1:nfds表示的是集合中最大文件描述符+1;
    参数2:readfds表示关心的读事件集合,不关心用NULL填充
    参数3:writefds表示关心的写事件集合,不关心用NULL填充
    参数4:exceptfds表示关心的其它事件集合,不关心用NULL填充
    参数5:timeout用来设置阻塞事件
                a, 设置为NULL,表示检测时一直阻塞,直到有事件准备就绪函数才返回
                b, 设置结构体的值
struct timeval {
    long tv_sec; /* seconds */
    long tv_usec; /* microseconds */
};
1) 成员的值都0,非阻塞方式检测;
2) 成员值为非零,有阻塞时间。
返回值:
    成功返回值准备就绪事件的个数;
    返回0表示检测超时
    失败返回-1,且修改errno的值。
void FD_CLR(int fd, fd_set *set); /* 将文件描述符fd从集合set中移除 */
int FD_ISSET(int fd, fd_set *set); /* 检测文件描述符fd是否在集合set,如果在返回非0,不在返回0 */
void FD_SET(int fd, fd_set *set); /* 将文件描述符fd添加到集合set中 */
void FD_ZERO(fd_set *set); /* 清空集合set */
2) 具体实现的思路:
    a,创建读事件集合readfds,并清空集合
        fd_set readfds;
        FD_ZERO(&readfds);
    b,将文件描述符listenfd添加到读事件集合readfds中;
        FD_SET(listenfd, &readfds);
    c,检测集合中是否有准备就绪的事件(阻塞方式检测,有事件准备就绪函数返回)
        ret = select(nfds, &readfds, NULL, NULL, NULL);
    d,得到准备就绪事件的文件描述符
        for(fd = 0; fd < nfds; fd++) {
        if (FD_ISSET(fd, &readfds)) {
    e,对fd进IO操作。
        }
    }
3) 特征:
    a,可以在一个任务中对多个阻塞io进程操作,谁先准备就绪,就操作谁。
    b,如果操作事件不同,需要定义多个集合;
    c,找到准备就绪的文件描述符的时候,需要从0遍历到最大的文件描述符。效率很低。

4.1示例代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous *//* 定义服务器初始化函数 */
int server_init(char *ip, short port)
{int ret;int listenfd;struct sockaddr_in srvaddr;/* 创建套接字文件 */listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd == -1) {perror("server_init->socket");return -1;}printf("listenfd = %d\n", listenfd);/* 绑定服务器的ip地址和端口号 */memset(&srvaddr, 0, sizeof(srvaddr));srvaddr.sin_family = AF_INET;srvaddr.sin_port = htons(port);if (ip == NULL)srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);elsesrvaddr.sin_addr.s_addr = inet_addr(ip);ret = bind(listenfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));if (ret == -1) {perror("server_init->bind");return -1;}printf("bind success\n");/* 启动监听 */ret = listen(listenfd, 1024);if (ret == -1) {perror("server_init->listen");return -1;}return listenfd;
}/* 定义服务器等待客户端的连接请求,建立连接 */
int server_wait_client_connect(int listenfd)
{int connfd;socklen_t addrlen;struct sockaddr_in cltaddr;//accept(listenfd, NULL, NULL);addrlen = sizeof(cltaddr);connfd = accept(listenfd, (struct sockaddr *)&cltaddr, &addrlen);if (connfd == -1) {perror("accept");return -1;}printf("IP : %s connet success connfd = %d\n", inet_ntoa(cltaddr.sin_addr), connfd);return connfd;
}int main()
{int ret;int listenfd;int connfd;char buf[256];fd_set readfds;fd_set rdfds;int nfds;int fd;/* 1. 服务器的初始化 */listenfd = server_init("127.0.0.1", 8888);//listenfd = server_init(NULL, 8888);if (listenfd == -1)exit(EXIT_FAILURE);printf("server init success\n");/* 创建集合,清空集合 */FD_ZERO(&readfds);/* 将文件描述符listenfd添加到读事件集合readfds中 */FD_SET(listenfd, &readfds);nfds = listenfd + 1;while(1) {/* c, 调用select函数,检测是否有准备就绪的事件,如果没有事件准备就绪,函数一直阻塞。如果有事件准备就绪函数返回;*/rdfds = readfds;ret = select(nfds, &rdfds, NULL, NULL, NULL);if (ret == -1) {perror("select");return -1;}for (fd = 0; fd < nfds; fd++) {/* 找到准备就绪事件的文件描述符 */if (!FD_ISSET(fd, &rdfds))continue;/* 准备就绪事件,进行IO操作 */if (fd == listenfd) { /* 监听套接字 *//* 2. 服务器等待客户端的连接请求,建立连接 */connfd = server_wait_client_connect(listenfd);if (connfd == -1)exit(EXIT_FAILURE);/* 连接成功,将文件描述符connfd添加到读事件集合readfds中 */FD_SET(connfd, &readfds);nfds = (connfd >= nfds ? connfd+1 : nfds);continue;} //if (fd == listenfd) end/* 通信套接字 *//* 3. 服务器处理客户端的数据请求,并处理数据,反馈处理结果 */memset(buf, 0, sizeof(buf));ret = read(fd, buf, sizeof(buf));if (ret == -1) {perror("server->read");return -1;} else if (ret == 0) {/* 客户端退出的时候,需要将套接字从集合中删除 */FD_CLR(fd, &readfds);close(fd);break;}printf("buf : %s\n", buf);ret = write(fd, buf, sizeof(buf));if (ret == -1) {perror("server->write");return -1;}} //for (fd = 0; fd < nfds; fd++) end} //while(1) endreturn 0;
}

IO模型(阻塞,非阻塞,多路复用......)相关推荐

  1. IO模型之非阻塞IO

    1. IO模型非阻塞 IO Linux下,可以通过设置socket使其变为 non-blocking.当对一个non-blocking socket执行读操作时,流程是这个样子: 从图中可以看出,当用 ...

  2. 五种IO模型:阻塞/非阻塞/复用/信号驱动/异步IO模型

    五种IO模型:阻塞/非阻塞/复用/信号驱动/异步IO模型 1. IO基本概念 1.1 IO概念 1.2 IO的两个阶段 1.2.1 IO的两个阶段-例子说明 1.2 IO种类 2. 五种IO模型 2. ...

  3. I/O: 阻塞非阻塞I/O 同步异步I/O

    我们知道,在Linux(UNIX)操作系统中,共有五种IO模型,分别是:阻塞IO模型.非阻塞IO模型.IO复用模型.信号驱动IO模型以及异步IO模型. 同步IO模型 阻塞IO模型 我们钓鱼的时候,有一 ...

  4. Java网络编程------IO模型的同步/异步/阻塞/非阻塞(1)

    IO模型的同步/异步/阻塞/非阻塞 一.同步/异步/阻塞/非阻塞 1.同步和异步 2.阻塞和非阻塞 3.同步.异步和阻塞.非阻塞组合 二.IO 1.I/O 2.阻塞IO和非阻塞IO 3.同步IO和同步 ...

  5. 异步就是异步,根本就没有 异步非阻塞IO这个说法。阻塞 非阻塞,同步I/O 异步I/O 的区别

    先给大家安利一下这个 https://www.ibm.com/developerworks/cn/linux/l-async/ 里面关于 异步非阻塞IO 是错的. 异步就是异步,别扯 异步阻塞 异步非 ...

  6. 面试必会系列 - 5.1 网络BIO、NIO、epoll,同步/异步模型、阻塞/非阻塞模型,你能分清吗?

    本文已收录至 Github(MD-Notes),若博客中图片模糊或打不开,可以来我的 Github 仓库,包含了完整图文:https://github.com/HanquanHq/MD-Notes,涵 ...

  7. AIO,BIO,NIO:同步阻塞式IO,同步非阻塞IO,异步非阻塞IO

    BIO,同步阻塞式IO,简单理解:一个连接一个线程 NIO,同步非阻塞IO,简单理解:一个请求一个线程 AIO,异步非阻塞IO,简单理解:一个有效请求一个线程 IO:阻塞IO BIO:同步阻塞IO.服 ...

  8. 两段文章清楚弄明白什么是异步IO、同步IO、同步阻塞IO、同步非阻塞IO、异步阻塞IO、异步非阻塞IO

    百科解释:异步IO_百度百科 先看2,再看1,会理解的更好! 1. 2.阻塞和非阻塞 # 阻塞和非阻塞关注的是程序在等待调用结果时的状态 # 阻塞调用是指调用结果返回之前,当前线程会被挂起.调用线程只 ...

  9. java nio io复用_java 非阻塞IO-java NIO-嗨客网

    Java的NIO教程 NIO 官方名称叫做 New IO,在 JDK 1.4 中相对于 BIO 的新 IO.但是也有很多人称之为 NON-BLOCKING IO.和 BIO 比较的话,叫做非阻塞 IO ...

  10. 同步异步阻塞非阻塞杂记

    版权声明:本文可能为博主原创文章,若标明出处可随便转载. https://blog.csdn.net/Jailman/article/details/78498458 gevent实现的协程是同步非阻 ...

最新文章

  1. 拒绝加班,办公电脑换新低至¥1999
  2. php 经纬度 摩卡 转换,WGS84经纬度坐标与WEB摩卡托坐标转换
  3. 1103 Integer Factorization (30 分)【难度: 中 / 爆搜】
  4. 自定义PocketMod的农历页面
  5. 如何防止插入删除表造成的数据库死锁
  6. MaxCompute SQL原理解析及性能调优
  7. “软考”遗失试卷全部追回 相关责任人接受审查
  8. matlab三角波发生器精度改为定点型,关于matlab simulink中三角波模块的问题!
  9. x的平方加y平加xy的java语言_面试被虐题:说说 JVM 系语言的函数式编程
  10. matlab2016b慢,Matlab 2016a/b中调用GPU速度巨慢的解决办法
  11. 常兴串口调试助手v3.6
  12. 【高并发】一文解密诡异并发问题的第一个幕后黑手——可见性问题
  13. 阿波罗登月计算机技术,你知道吗,阿波罗登月用的计算机还不如你家计算器!...
  14. java调用dll 指针参数_java调用c dll,指针参数和结构体参数搞定
  15. 雷林鹏最人性化访谈:做投资不仅仅是要赚钱,要成为有价值的人
  16. 数据结构笔记_34 赫夫曼编码压缩、解压文件
  17. 我的世界服务器货币充值系统,《我的世界》中国版正式开启了充值功能
  18. LMS151-10100单线激光雷达与RealSense双目相机的联合标定
  19. 点到线段直线的距离, 直线与直线的关系 直线与线段的关系
  20. 用photoshop拼接一个七巧板图案

热门文章

  1. 【LINUX-python】PATH、sys.path、PYTHONPATH
  2. 小尺寸android 手机推荐,喜欢小屏安卓手机的来看看,这三款便宜又好用
  3. esp32入门手册学习
  4. 五剑同辉 聚力安全:绿盟科技五大安全实验室震撼发布
  5. 1761:神奇的口袋(2)
  6. [JS]JSON字符串与JS对象的转换
  7. 压测、压力测试分析、UV、PV、通用性能提高、并发
  8. 携程在线网页制作(flex布局)(静态页面)
  9. 代号斗罗显示服务器暂未开放,代号:斗罗内测版
  10. 过年烟花特效+鼠标滑过+樱花特效