网络编程:IO多路复用(五个IO模型)
创始人
2024-09-26 15:51:34
0

   1. 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力
    
   2. 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标的输入、中断信号等等事件,再比如web服务器如nginx,需要同时处理来来自N个客户端的事件。
    
    逻辑控制流在时间上的重叠叫做 并发
    
    而CPU单核在同一时刻只能做一件事情,一种解决办法是对CPU进行时分复用(多个事件流将CPU切割成多个时间片,不同事件流的时间片交替进行)。在计算机系统中,我们用线程或者进程来表示一条执行流,通过不同的线程或进程在操作系统内部的调度,来做到对CPU处理的时分复用。这样多个事件流就可以并发进行,不需要一个等待另一个太久,在用户看起来他们似乎就是并行在做一样。
    
    2. 使用并发处理的成本:
    线程/进程创建成本
    CPU切换不同线程/进程成本 Context Switch
    多线程的资源竞争
    
    有没有一种可以在单线程/进程中处理多个事件流的方法呢?一种答案就是 IO多路复用。

    因此IO多路复用解决的本质问题是在用更少的资源完成更多的事(read\write)。

IO模型
    1、阻塞IO  
    2、非阻塞IO    EAGAIN  忙等待 errno(提高效率)
    3、信号驱动IO  SIGIO 用的相对少(了解)
    4、并行模型    进程,线程
    5、IO多路复用  select、poll、epoll(效率相对高些) 

一、阻塞io

二、非阻塞io

 非阻塞IO ===》在阻塞IO的基础上 调整其为 不再阻塞等待。
 在程序执行阶段调整文件的执行方式为非阻塞:
        fcntl() ===>动态调整文件的阻塞属性

    #include
    #include
    int fcntl(int fd, int cmd, ... /* arg */ );
    功能:修改指定文件的属性信息。
    参数:fd    要调整的文件描述符
              cmd 要调整的文件属性宏名称
               ...   可变长的属性值参数
    返回值:成功  不一定,看cmd
                  失败  -1;

    eg:修改文件的非阻塞属性:
        int flag ;
        flag  = fcntl(fd,F_GETFL,0);  ///获取fd文件的默认属性到flag变量中。
        flag  = flag | O_NONBLOCK;  ///将变量的值调整并添加非阻塞属性
        fcntl(fd,F_SETFL,flag);   ///将新属性flag设置到fd对应的文件生效。

        以上代码执行后的阻塞IO将变成非阻塞方式。

 fifo_w.c

#include  #include  #include  #include  #include  #include  #include  #include  int main(int argc, char *argv[]) {     int ret = mkfifo("myfifo",0666);         if(-1 == ret)     {         //如果是管道文件已存在错误,让程序继续运行         if(EEXIST== errno)         {          }else          {             perror("mkfifo");             exit(1);         }     }     //open 会阻塞,等到另一端读段打开,解除阻塞     int fd = open("myfifo",O_WRONLY);     if(-1 == fd)     {         perror("open");         exit(1);     }     while(1)     {         char buf[256]="hello,fifo,test";         write(fd,buf,strlen(buf));         sleep(3);     }     close(fd);      return 0; }

fifo_r.c

#include  #include  #include  #include  #include  #include  #include  #include   int main(int argc, char *argv[]) {     int ret = mkfifo("myfifo",0666);         if(-1 == ret)     {         //如果是管道文件已存在错误,让程序继续运行         if(EEXIST== errno)         {                  }else          {             perror("mkfifo");             exit(1);         }     }      int fd = open("myfifo",O_RDONLY);     if(-1 == fd)     {         perror("open");         exit(1);     }     int flag = fcntl(fd,F_GETFL);     flag = flag|O_NONBLOCK  ;      fcntl(fd,F_SETFL,flag);      flag = fcntl(0,F_GETFL);     fcntl(0,F_SETFL,flag|O_NONBLOCK);     while(1)     {         char buf[256]={0};         if(read(fd,buf,sizeof(buf))>0)         {             printf("fifo %s\n",buf);         }         bzero(buf,sizeof(buf));         if(fgets(buf,sizeof(buf),stdin))         {             printf("terminal:%s\n",buf);         }     }     close(fd);     //remove("myfifo");      return 0; }

三、信号驱动io

文件描述符需要追加 O_ASYNC 标志。
设备有io事件可以执行时,内核发送SIGIO信号。

 1)追加标志
        int flag ;
        flag  = fcntl(fd,F_GETFL,0);
        fcntl(fd,F_SETFL,flag | O_ASYNC);    
 2)设置信号接收者
        fcntl(fd,F_SETOWN,getpid());//常用设置
3)对信号进行捕获
        signal(SIGIO,myhandle);

fifo_w.c

#include  #include  #include  #include  #include  #include  #include  #include  int main(int argc, char *argv[]) {     int ret = mkfifo("myfifo",0666);         if(-1 == ret)     {         //如果是管道文件已存在错误,让程序继续运行         if(EEXIST== errno)         {          }else          {             perror("mkfifo");             exit(1);         }     }     //open 会阻塞,等到另一端读段打开,解除阻塞     int fd = open("myfifo",O_WRONLY);     if(-1 == fd)     {         perror("open");         exit(1);     }      while(1)     {         char buf[256]="hello,fifo,test";         write(fd,buf,strlen(buf));         sleep(3);     }     close(fd);      return 0; }

 fifo_r.c

#include  #include  #include  #include  #include  #include  #include  #include  #include  int fd; void handle(int num) {     char buf[256]={0};     read(fd,buf,sizeof(buf));     printf("fifo %s\n",buf);  } int main(int argc, char *argv[]) {     signal( SIGIO,handle);     int ret = mkfifo("myfifo",0666);         if(-1 == ret)     {         //如果是管道文件已存在错误,让程序继续运行         if(EEXIST== errno)         {                  }else          {             perror("mkfifo");             exit(1);         }     }      fd = open("myfifo",O_RDONLY);     if(-1 == fd)     {         perror("open");         exit(1);     }     int flag = fcntl(fd,F_GETFL);     fcntl(fd,F_SETFL ,flag|O_ASYNC);      fcntl(fd,F_SETOWN, getpid() );     while(1)     {         char buf[256]={0};         fgets(buf,sizeof(buf),stdin);         printf("terminal:%s\n",buf);     }     close(fd);     //remove("myfifo");      return 0; }

四、并行

五、io多路复用

1.阻塞版

select循环服务器 ===> 用select函数来动态检测 有数据流动的文件描述符
    #include
    #include
    #include
    #include

    int select(int nfds, fd_set *readfds, fd_set *writefds,
                fd_set *exceptfds,struct timeval *timeout);
    功能:完成指定描述符集合中有效描述符的动态检测。
              该函数具有阻塞等待功能,在函数执行完毕后,目标测试集合中将只保留最后有数据的描述符。

    参数:nfds 描述符的上限值,一般是链接后描述符的最大值+1;
               readfds 只读描述符集
              writefds 只写描述符集
              exceptfds 异常描述符集
      以上三个参数都是 fd_set * 的描述符集合类型
             timeout  检测超时 如果是NULL表示一直检测不超时 。

    返回值:超时  0
                  失败 -1
                  成功 >0

        为了配合select函数执行,有如下宏函数:
        void FD_CLR(int fd, fd_set *set);
        功能:将指定的set集合中编号为fd的描述符号删除。

        int  FD_ISSET(int fd, fd_set *set);
        功能:判断值为fd的描述符是否在set集合中,如果在则返回真,否则返回假。

        void FD_SET(int fd, fd_set *set);
        功能:将指定的fd描述符,添加到set集合中。

        void FD_ZERO(fd_set *set);
        功能:将指定的set集合中所有描述符删除。 

2.超时版

3.epoll

相关内容

热门资讯

安卓手机好的系统,安卓手机操作... 你有没有发现,现在手机市场上的安卓手机真是琳琅满目,让人挑花了眼。不过,你知道吗?在这些安卓手机中,...
安卓系统mac电脑配置,打造安... 亲爱的电脑迷们,你是否曾想过,你的苹果笔记本里也能装上安卓系统?是的,你没听错!今天,就让我带你一起...
状元郎平板安卓系统,引领平板教... 你有没有想过,一款平板电脑,竟然能让你在学习之余,还能畅游安卓世界的海洋?没错,今天我要跟你聊聊的就...
安卓系统哪个传奇好玩,畅玩经典... 手机里的游戏可是咱们休闲娱乐的一大法宝,尤其是安卓系统,那丰富的游戏资源简直让人挑花眼。今天,就让我...
联众支持安卓系统吗,“联众PD... 斗地主爱好者们,是不是在为找不到一款好玩的斗地主游戏而烦恼呢?别急,今天我要给大家揭秘一个好消息——...
康佳电视安卓系统太卡,康佳电视... 亲爱的电视迷们,你们有没有遇到过这样的烦恼:家里的康佳电视用着用着就变得像蜗牛一样慢吞吞的,让人抓狂...
ios对比安卓系统流畅,流畅体... 你有没有发现,用手机的时候,有时候iOS系统就像个优雅的舞者,而安卓系统则像个活力四射的少年?没错,...
安卓系统占用内存小,深度解析优... 你有没有发现,手机用久了,就像人一样,会变得“臃肿”起来?尤其是安卓系统,有时候感觉就像一个超级大胃...
安卓系统怎么下载jdk,JDK... 你有没有想过,在安卓手机上也能编写Java程序呢?没错,就是那种在电脑上写代码的感觉,现在也能在手机...
安卓系统调手机亮度,轻松掌握手... 手机屏幕亮度总是让你眼花缭乱?别急,今天就来手把手教你如何轻松调节安卓系统的手机亮度,让你的手机屏幕...
学习机安卓系统双系统,安卓系统... 你有没有想过,学习机也能玩转安卓系统?没错,就是那个我们平时用来刷剧、玩游戏、看新闻的安卓系统!现在...
安卓系统有哪些兼职,盘点热门兼... 你有没有想过,在手机上也能轻松赚钱呢?没错,就是那个我们每天都离不开的安卓系统,它不仅能让你畅游网络...
别致影音下载安卓系统,轻松享受... 你有没有想过,在这个信息爆炸的时代,找到一款既别致又实用的影音下载APP,简直就像在茫茫人海中找到那...
安卓车机系统和手机系统,共筑智... 你有没有发现,现在汽车也越来越智能了?这不,车机系统都开始流行起来,而且很多车企都选择了安卓系统。那...
爱情银行ios系统与安卓系统,... 亲爱的读者们,今天咱们来聊聊一个让无数人心动的话题——爱情银行iOS系统与安卓系统!想象爱情银行就像...
车载wce系统和安卓系统区别,... 亲爱的车友们,你们有没有想过,为什么你的车载导航有时候会像老牛拉车一样慢吞吞,有时候又像兔子一样活泼...
安卓系统常见app取证,深度解... 你有没有想过,手机里的那些小玩意儿,其实可能藏着大大的秘密呢?没错,就是那些我们每天不离手的安卓系统...
苹果云照片安卓系统,苹果云照片... 你有没有想过,那些在苹果手机上美美哒的照片,怎么才能搬到安卓手机上呢?别急,今天就来给你揭秘这个神奇...
ios系统跟安卓系统都是美国,... iOS与安卓:美国科技的双雄争霸在当今这个数字化的世界里,智能手机已经成为了我们生活中不可或缺的一部...
深度系统可以装安卓,系统兼容安... 亲爱的读者们,你是否曾想过,在电脑上也能畅玩安卓游戏,享受安卓应用带来的便捷?现在,这个梦想成真啦!...