精华内容
下载资源
问答
  • 网络IO模型

    千次阅读 2014-07-03 21:12:28
    本文内容目录: 一:网络IO模型的分类,各个模型的定义和特点 er

                                                                                                          网络IO模型

    切记:IO特性不是由接口决定,而是由描述符(fd)的属性决定

    本文内容目录:

    一:网络IO模型的分类,各个模型的定义和特点

    二:每个模型的原理和比较

    三:每个模型的编程步骤、编程实例,以及注意细节。



    一:网络IO模型的分类,各个模型的定义和特点

    在网络IO模型中,有五种模型: 

        * blocking IO              阻塞IO
        * nonblocking IO        非阻塞IO
        * IO multiplexing         IO多路复用
        * signal driven IO       信号驱动IO
        * asynchronous IO      异步IO



    二:每个模型的原理

    对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,它会经历两个阶段:

      1)等待数据准备 (Waiting for the data to be ready)
      2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)

     (1)、阻塞IO(blocking IO


                                                     

                                                                                                                阻塞模型   

           当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来


         我们注意到,大部分的socket接口都是阻塞型的。所谓阻塞型接口是指系统调用(一般是IO接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。
        实际上,除非特别指定,几乎所有的IO接口 ( 包括socket接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用send()的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。


    (2)、非阻塞IO(non-blocking IO

                                     

                                                                                     非阻塞模型

    从图中可以看出,当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。
        所以,在非阻塞式IO中,用户进程其实是需要不断的主动询问kernel数据准备好了没有。

        非阻塞的接口相比于阻塞型接口的显著差异在于,在被调用之后立即返回。使用如下的函数可以将某句柄fd设为非阻塞状态


     (3)、多路复用IO(IO multiplexing)

                                    

                                                                                  多路复用IO的模型

     当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
        这个图和blocking IO的图其实并没有太大的不同,事实上还更差一些。因为这里需要使用两个系统调用(select和recvfrom),而blocking IO只调用了一个系统调用(recvfrom)。但是,用select的优势在于它可以同时处理多个connection。(多说一句:所以,如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)
        在多路复用模型中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。因此select()与非阻塞IO类似。

                                                                

                                                                                             多路复用模型的一个执行周期

    实际上,Linux内核从2.6开始,也引入了支持异步响应的IO操作,如aio_read, aio_write,这就是异步IO。


    (4)、信号驱动IO (ignal driven IO)  

                                        

     首先我们允许套接口进行信号驱动I/O,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据


    (5)、 异步IO (asynchronous IO     )

                              

       调用aio_read函数,告诉内核描述字,缓冲区指针,缓冲区大小,文件偏移以及通知的方式,然后立即返回。当内核将数据拷贝到缓冲区后,再通知应用程序。这个操作和信号驱动的区别就是:异步模式等操作完毕后才通知用户程序而信号驱动模式在数据到来时就通知用户程序。


    五种IO模型的比较:

    前四种模型的区别是第一阶段,第二阶段基本相同,都是将数据从内核拷贝到调用者的缓冲区。而异步I/O的两个阶段都不同于前四个模型。

                            



    以上部分内容的参考文献:

                       http://blog.csdn.net/blueboy2000/article/details/4485874

                       http://blog.csdn.net/zhoudaxia/article/details/8974779


    三:每个模型的编程步骤、编程实例,以及注意细节。



    头文件:head.h(下面几种IO的公用头文件)

    <span style="font-size:14px;">#ifndef _HEAD_H_
    #define _HEAD_H_ 
    
    #include <stdio.h>
    #include <sys/types.h>	       /* See NOTES */
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <strings.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include<errno.h>
    #include<error.h>
    #define BUFF_SIZE 128 
    #define SER_IP  "127.0.0.1"
    #define SER_PORT 50001
    
    #define ECHO_PORT 7 
    
    #endif </span>


    非阻塞的server.c

    <span style="font-size:14px;">#include "head.h"
    int main(int argc, const char *argv[])
    {
    	int sockfd,n ;
    	char buf[BUFF_SIZE];	
    	struct  sockaddr_in  peer_addr;
    	socklen_t addrlen = sizeof(peer_addr);
    	if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0)))
    	{
    		perror("socket");
    		return -1;
    	}
    
    	//填充服务端地址结构体
    	struct sockaddr_in ser_addr;
    	bzero(&ser_addr,sizeof(ser_addr)); 
    
    	ser_addr.sin_family = AF_INET;
    	ser_addr.sin_port =  htons(SER_PORT);
    	ser_addr.sin_addr.s_addr = inet_addr(SER_IP);
    	
    	//必须绑定 
    	if(-1 == bind(sockfd, (struct sockaddr *)&ser_addr,sizeof(ser_addr)) )
    	{
    		perror("bind");
    		return -1;
    	}
    	
    	//1. 获取文件状态标志位 
    	int flag = fcntl(0,F_GETFL);
    	printf("set before,stdin flag = %d\n ",flag);
    
    	int flag1=fcntl(3,F_GETFL);
    	printf("set before,socket flag1=%d\n",flag1);
    	//2.添加非阻塞特性,首先获取器描述符的属性,然后进行或运算,这样不会覆盖以前的描述符属性
    	fcntl(0,F_SETFL, flag | O_NONBLOCK);//将标准输入IO(stdin)设置为非阻塞状态 ,
      fcntl(3,F_SETFL,flag1 | O_NONBLOCK);//将套接字设置为非阻塞状态, 也可以写成fcntl(sockfd,F_SETFL,flag1 | O_NONBLOCK);
      //为什么是3呢?  因为0是标准输入 stdin  1是标准输出stdout  2是errno  
      //这些在默认的情况下,系统是将其打开的,套接字自然就是3了,如果继续打开一个IO,其值是4,以此类推
      
    
    	
    
    	flag = fcntl(0,F_GETFL);
    	flag1=fcntl(3,F_GETFL);
    	printf("set after,stdin flag = %#o \n ",flag);
    	printf("set after,socket flag1=%#o \n",flag1);
    
         int num;
    	//非阻塞:接收客户端数据并且还要读取当前终端的输入 
    	//实现终端输入和接受数据并发执行 
    	while(1)
    	{
    	   if(NULL!=fgets(buf,BUFF_SIZE,stdin))
    	   {
    	    	printf("buf = %s\n",buf);
    	   }
    
    		if( -1 == (n = recvfrom(sockfd,buf,BUFF_SIZE,0,(struct sockaddr *)&peer_addr,&addrlen)))
    		{
    		  if(errno!=EAGAIN)
    		  {
    			  perror("recvfrom");
    		    	return -1;
    		  }
    		}         
    		if(n>0)
    		printf("peer_addr IP :  %s port: %d \n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
    	}
    	return 0;
    }
    </span>


    信号驱动IO的server.c

    #include "head.h"
    int sockfd,n ;
    struct  sockaddr_in  peer_addr;
    socklen_t addrlen = sizeof(peer_addr);
    
    void handler(int signum)
    {
    	char buf[BUFF_SIZE];
    	bzero(buf,sizeof(buf));
    
    		if( -1 == (n = recvfrom(sockfd,buf,BUFF_SIZE,0,(struct sockaddr *)&peer_addr,&addrlen)))
    		{
                perror("recvfrom ");
    					  return ;		 
    		}
    
    		printf("------%s-------\n",buf);
    }
    
    int main(int argc, const char *argv[])
    {
    	char buf[BUFF_SIZE];	
    
    	if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0)))
    	{
    		perror("socket");
    		return -1;
    	}
    
    	//填充服务端地址结构体
    	struct sockaddr_in ser_addr;
    	bzero(&ser_addr,sizeof(ser_addr)); 
    
    	ser_addr.sin_family = AF_INET;
    	ser_addr.sin_port =  htons(SER_PORT);
    	ser_addr.sin_addr.s_addr = inet_addr(SER_IP);
    	
    	//必须绑定 (在tcp或udp中,服务器端必须调用bind,进行和IP地址的绑定)
    	if(-1 == bind(sockfd, (struct sockaddr *)&ser_addr,sizeof(ser_addr)) )
    	{
    		perror("bind");
    		return -1;
    	}
    	
      int flag=	fcntl(sockfd,F_GETFL);
      fcntl(sockfd,F_SETFL,flag|O_ASYNC);  //设置套接字允许异步接收
        
      fcntl(sockfd,F_SETOWN,getpid());   //将该信号和本进程绑定,即只允许该进程来相应对应的信号
      /*
      在 fcntl(sockfd,F_SETOWN,getpid()); 中指定sockfd的原因?
      假如在本程序中,有两个套接字,到底由哪个进行和本进程一起与外部程序进行通信呢?所以要指定sockfd  
      */
    
    	signal(SIGIO,handler);//注册信号处理函数
    
    	while(1)
    	{
    	   if(NULL!=fgets(buf,BUFF_SIZE,stdin))
    	   {
    	    	printf("buf = %s\n",buf);
    	   }
    	}
    	return 0;
    }
    



    多路复用IO的server.c

    #include "head.h"
    /*
    多路复用IO,类似与火车站
    其中火车站的多个进站口就是检测表
    有动车可以就绪,有普通列车可以就绪
    站长在站口进行监听,查看,然后让已经到达的火车视为就绪状态(就绪出发)
    不出站的火车永远都是就绪状态,因此要判断哪个火车到达后,就视为就绪,然后及时让其出站。
    
    在这里,检测表就是火车站的多个站口。各种火车类型就是不同的描述符类型
    列车长得监听和查看就是select
    火车的进站就是描述符就绪
    火车出站就是对应的描述符数据被取走
    */
    int main(int argc, const char *argv[])
    {
    	int sockfd,n ;
    	char buf[BUFF_SIZE];
    	
    	struct  sockaddr_in  peer_addr;
    	socklen_t addrlen = sizeof(peer_addr);
    
    	if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0)))
    	{
    		perror("socket");
    		return -1;
    	}
    
    	//填充服务端地址结构体
    	struct sockaddr_in ser_addr;
    	bzero(&ser_addr,sizeof(ser_addr)); 
    
    	ser_addr.sin_family = AF_INET;
    	ser_addr.sin_port =  htons(SER_PORT);
    	ser_addr.sin_addr.s_addr = inet_addr(SER_IP);
    	
    	//必须绑定 
    	if(-1 == bind(sockfd, (struct sockaddr *)&ser_addr,sizeof(ser_addr)) )
    	{
    		perror("bind");
    		return -1;
    	}
    	
         /*
    	  *多路复用服务器的创建步骤:
    	  *1建立检测表
    	  *2将需要监听的描述符加入该表
    	  *3监听该表
    	  *4判断该表中的就绪描述符,进行对应的读数据
          *
    	  * */
          
    	// 建立检测表
           fd_set readfds;
    	   bzero(&readfds,sizeof(readfds));
       //将描述符加入该表
        FD_SET(0,&readfds);
    	  FD_SET(sockfd,&readfds);//此时检测表的相应位被置1
    	  
    	  //sleep(10);  可以在此加入睡眠,让多个描述符同时输入就绪状态,查看t会发生变化,相应就绪的会被置为1
    
    	  int t=select(sockfd+1,&readfds,NULL,NULL,NULL); //select之后,只有就绪的相应为设置为1,其他没有就绪的描述符新、相应位为0了
    
    	  printf("t=%d------------------\n",t);
        
      char rbuf[BUFF_SIZE];	
    	while(1)
    	{     
              bzero(rbuf,sizeof(rbuf));
             printf("stdin FD_ISSET()===%d\n",FD_ISSET(0,&readfds));
             printf("sockfd FD_ISSET()===%d\n",FD_ISSET(sockfd,&readfds));
    		 if(FD_ISSET(0,&readfds))
    		 fgets(rbuf,sizeof(rbuf),stdin);
    	}
    
    	return 0;
    }
    


                                                                                                未经允许,禁止转载

    展开全文
  • 同步、异步、阻塞、非阻塞,当这些网络IO名词堆到一起时难免使编程初学者感到困惑,这里我们就来为大家总结网络IO模型与select模型的Python实例讲解:
  • 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO
  • 4种网络IO模型

    2019-06-28 09:14:21
    4种网络IO模型 当一个网络*IO*发生时,它会涉及到两个系统对象,一个是调用这个IO的进程,另一个是系统内核。当一个read操作发生时,它会经历两个阶段:(1)等待数据准备;(2)将数据从内核拷贝到进程。 为了解决网络...

    4种网络IO模型

    当一个网络*IO*发生时,它会涉及到两个系统对象,一个是调用这个IO的进程,另一个是系统内核。当一个read操作发生时,它会经历两个阶段:(1)等待数据准备;(2)将数据从内核拷贝到进程。
    

    为了解决网络IO问题,有四种网络IO模型:(1)阻塞IO模型(2)非阻塞IO模型(3)多路复用IO模型(4)异步IO模型

    阻塞IO模型

    在Linux中,默认情况下所有的socket都是阻塞的,一个读操作流程如图1所示
    

    图1
    阻塞和非阻塞的概念描述的是用户线程调用内核IO操作方式:阻塞是指IO操作需要彻底完成后才能返回用户空间;而非阻塞是指IO操作被调用后立即返回给用户一个状态值,不需要等到IO操作彻底完成。
    大部分的socket接口都是阻塞型的。所谓阻塞型指系统调用时,却不返回调用结果,并让当前线程一直处于阻塞状态,只有当该系统调用获得结果或者超时出错时才返回结果。除非特别指定,几乎所有IO接口都是阻塞型的。这个网络编程带来很大的问题,如在调用send()的同时,线程处于阻塞状态,则在此期间,线程将无法执行任何运算或响应任何网络请求。
    一个简单的改进方案是在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他连接。如果同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占用系统资源,降低系统对外界响应的效率,而线程与进程本身也容易进入假死状态。很多程序员会考虑使用“线程池”或“连接池”。“线程池”旨在降低创建和销毁线程的频率,使其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。“连接池”指维持连接的缓存池,尽量重用已有的连接,降低创建和关闭连接的频率。但是,“线程池”和“连接池”只是在一定程度上缓解了频繁调用IO接口带来的资源占用。而且“池”的大小是有限制的。面对大规模的服务请求,多线程模型也会遇到瓶颈,可以用非阻塞模型尝试解决这个问题。

    非阻塞模型

    在Linux下,可以通过设置socket使IO变为非阻塞。对一个非阻塞的socket执行read操作时,流程如图2
    

    图2
    从图中可以看出,用户进程发出read操作时,如果内核中的数据还没有准备好,它不会block用户进程,而是立刻返回一个错误。从用户的角度,它发起一个read操作后,并不需要等待,而是马上得到一个结果。
    服务器线程通过循环调用recv()接口,可以在单个线程内实现对所有连接数据的接收工作。但是因为循环调用recv()将大幅度占用CPU使用率,此外,recv()更多的是起到“操作是否完成”的作用,实际操作系统提供了更高效的检测“操作是否完成”作用的接口,例如select()多路复用模式,可以一次检测到多个连接是否活跃。

    多路IO复用模型

    多路IO复用,也称事件驱动IO。它的基本原理就是有个函数(如select)会不断地轮询所负责的所以socket,当某个socket有数据到达了,就通知用户进程。多路IO复用模型的流程如图3所示
    

    图3
    这个模型和阻塞IO的模型其实没有太大区别,事实上还更差一些。因为它需要两个系统调用(select 和 recvfrom),而阻塞IO只调用了一个系统调用(recvfrom)。但是,用select 的优势在于它可以同时处理多个连接。

    异步IO模型

    异步IO模型的流程图如图4所示
    

    图4
    用户进程发起read操作之后,立刻就可以开始去做其他的事,从内核的角度,当它收到一个异步的read请求操作之后,首先会立刻返回,所以不会对用户进程产生任何阻塞。
    各种IO模型的比较
    图5

    展开全文
  • 文章目录1.IO读写原理1.1 内核...网络IO模型一共介绍以下四种: 同步阻塞IO、同步非阻塞IO、IO多路复用和异步IO。 1.IO读写原理 文件的读写还是socket读写,在Java应用层开发,都是input或者output处理 用户程序进行IO操


    网络IO模型一共介绍以下四种: 同步阻塞IO、同步非阻塞IO、IO多路复用和异步IO。

    1.IO读写原理

    文件的读写还是socket读写,在Java应用层开发,都是input或者output处理

    用户程序进行IO操作,依赖于底层的IO实现,主要是**底层的 read&write两大系统调用:**

    • read系统调用指的是将数据从内核缓冲区复制到进程缓冲区
    • write系统调用指的是把数据从进程缓冲区复制到内核缓冲区

    这也就是说,上层程序的IO操作,实际上不是物理设备的级别的读写,而是缓存的复制。

    1.1 内核缓冲区和进程缓存区

    1.1.1 用户进程和操作系统

    用户进程(N) -> 处于用户态(用户空间)
    系统空间 -> 内核态

    在用户态需要访问系统资源,借助于内核态,系统资源主要有:

    • 1)cpu:控制一个程序的执行
    • 2)输入输出:一切都是流,所有流都是需要借助内核态
    • 3)进程管理:进程创建、销毁、阻塞、唤醒之间的调度
    • 4)内存:内存的申请、释放
    • 5)进程间通信:进程之间不能够相互访问内存,所以进程之间的交互需要通信,通信也是一种资源

    以上所提到的系统资源,在用户进程中是无法被直接访问的,只有通过操作系统来访问,所以把操作系统访问这些资源的这一功能称之为系统调用

    1.1.2 缓冲区的目的

    为了减少频繁的系统IO调用

    系统调用需要从用户态切换到内核态,切换之后保存用户进程的数据状态等信息,结束调用之后需要回复之前的信息为了减少这种损耗的时间,还有损耗性能的时间, 所以出现了缓冲区

    有了缓冲区,操作系统使用read函数内核缓冲区复制到进程缓冲区write函数进程缓冲区复制到内核缓冲区,只有缓冲区中的数据达到一定的量再IO的系统,提升性能.

    用户程序的IO操作,大部分情况下,并没有进行实际的IO操作,而是进程缓冲区和内核缓冲区之间直接进行数据交换

    1.2 Java读写IO底层流程

    在这里插入图片描述
    如果是在Java服务器端,完成一个Socket请求和详情,完整的流程如下:

    • 客户端请求:Linux通过网卡读取客户端请求数据,将数据读到内核缓冲区
    • 获取请求数据:Java服务器通过read系统调用,从linux内核缓冲区读取数据,在送入Java进程缓冲区
    • 服务端业务处理:Java服务器在自己的用户空间中处理客户端的请求。
    • 服务端返回数据:Java服务器完成处理后,构建好响应数据,将这些数据从用户缓冲区写入内核缓冲区。这里用到write系统调用
    • 发送给客户端:Linux内核通过网络IO,将内核缓冲区中的数据写入网卡,网卡底层通信协议,会将数据发送给目标客户端。

    2.四种主要的IO模型

    2.1 基本概念

    2.1.1 阻塞与非阻塞

    • 阻塞IO:需要内核IO操作彻底完成之后,才返回到用户空间,执行用户的操作

    • 非阻塞IO:不需要等待内核IO操作彻底完成之后,才返回到用户空间

    • 阻塞/非阻塞指的是用户空间程序的执行状态

      换句话说就是

    • 阻塞:用户空间(调用线程)死等内核IO,这期间什么都不干。

    • 非阻塞:用户空间(调用线程)拿到内核返回的状态就直接返回自己的空间,IO操作可以干就干,不可以干就去干别的事情。

    2.1.2 同步与异步

    • 同步IO:用户空间线程和内核空间线程的交互,用户空间线程是主动发起IO请求的一方,内核空间是被动接收的一方
    • 异步IO:与上面刚好相反,内核空间是主动发起IO请求的一方,用户空间的线程是被动接受方。

    2.1.3 四种IO模型

    • 同步阻塞IO(Blocking IO)
    • 同步非阻塞IO(Non-Blocking IO)
    • IO多路复用(IO Multiplexing)
    • 异步IO(Asynchronous IO)

    2.2 同步阻塞IO(Blocking IO)

    在同步阻塞IO模型中,程序用IO调用开始,直到系统调用返回,在这段时间内,进程是阻塞。直到返回成功后,应用程序开始处理用户空间的缓存区数据.主要分为两个阶段:

    • 等待数据就绪:网络IO就是等待远端数据陆续到达磁盘IO就是等到磁盘数据从磁盘读取到内核缓冲区
    • 数据复制: 用户空间的程序没有权限直接读取内核缓冲区的数据(操作系统处于安全的考虑),因此内核与需要把内核缓冲区的数据复制一份到进程缓冲区

    同步阻塞IO模型如下图所示:

    在这里插入图片描述
    阻塞IO的特点是:在内核进行IO执行的两个阶段用户线程都被阻塞了。

    2.3 同步非阻塞IO(None Blocking IO)

    将Socket设置为non-blocking,当前连接就变成了非阻塞IO。使用非阻塞模式的IO读写,叫做同步非阻塞IO(None Blocking IO),简称NIO模型

    同步非阻塞IO模型中,会出现下面几种情况:

    • 内核缓冲区没有数据的情况下,系统调用会立即返回,返回一个调用失败的信息。这样请求就不会阻塞
    • 用户线程需要不断的发起IO系统调用测试内核数据是否准备好。
    • 内核缓冲区有数据的情况下,是阻塞的。直到内核缓冲区的数据全部复制到进程缓冲区,系统调用成功。

    同步非阻塞IO模型如下图所示:在这里插入图片描述
    同步非阻塞IO特点:程序需要不断的进行IO系统调用轮询数据是否准备好,如果没有准备好,就继续轮询

    2.4 IO多路复用模型(IO Multiplexing)

    在IO多路复用模型中,引入了一种新的系统调用select/epoll,查询IO的就绪状态。通过该系统调用可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓存区可读/可写),内核能够将就绪的状态返回给应用程序。随后,应用程序根据就绪的状态,进行相应的IO系统调用。

    在IO多路复用模型中通过select/epoll系统调用,单个应用程序的线程,可以不断轮询成百上千的socket连接当某个或者某些socket网络连接有IO就绪的状态,就返回对应的可以执行的读写操作

    IO多路复用模型如下图所示:
    在这里插入图片描述

    IO多路复用模型的特点:IO多路复用模型涉及两种系统调用,一种是就绪查询(select/epoll),一种是IO操作。

    多路复用IO也需要轮询。负责就绪状态查询系统调用的线程,需要不断的进行select/epoll轮询,查找出达到IO操作就绪的socket连接

    2.5 异步IO模型(Asynchronous IO)

    异步IO模型(Asynchronous IO)简称AIO,其基本流程为:用户线程通过系统调用,向内核注册某个IO操作。内核在整个IO操作(包括数据准备、数据复制)完成后,通知用户程序,执行后续的业务操作。

    在异步IO模型中,整个内核的数据处理过程中,包括内核将数据从网络物理设备(网卡)读取到内核缓存区、将内核缓冲区的数据复制到用户缓冲区,用户程序都不需要阻塞

    异步IO模型如下图所示:
    在这里插入图片描述

    异步IO模型的特点:在内核等待数据复制数据的两个阶段,用户线程都不是阻塞的。当内核的IO操作(等待数据和复制数据)全部完成后,内核会通知应用程序读数据

    3. 四种IO模型的优缺点

    3.1 同步阻塞IO

    • 优点:程序开发简单;在阻塞等待数据期间,用户线程挂起,不占用CPU资源
    • 缺点一个线程维护一个IO流的读写,在高并发应用场景下,需要大量的线程来维护大量的网络连接,内存、线程切换开销会十分巨大,BIO模型在高并发场景下是不可用的

    3.2 同步非阻塞IO

    • 优点:内核缓冲区没有数据的情况下,发起的系统调用不会阻塞,用户程序不会阻塞,实时性较好。
    • 缺点:需要不断地重复地发起IO调用,这种不断轮询,不断询问内核的方式,会占用CPU大量的时间,资源利用率比较低;在内核缓冲区有数据的情况下,也是阻塞的。NIO模型在高并发场景下是不可用的

    3.3 IO多路复用

    • 优点select/epoll可以同时处理成百上千的连接,与之前的一个线程维护一个连接相比,IO多路复用则不需要创建线程,也就不需要维护,从而减少系统开销.
    • 缺点select/epoll系统调用,属于阻塞的模式。读写事件就绪之后,用户自己进行读写,这个读写过程也是阻塞的

    3.4 异步IO

    • 优点内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的
    • 缺点:需要事件的注册,就需要操作系统。
    展开全文
  • nginx网络IO模型

    千次阅读 2017-08-01 10:36:19
    nginx支持很多的网络IO模型,不同的平台支持的IO模型也有一定的区别,nginx正常情况下会根据平台自动选择有效的模型, 也可以使用use命令指定需要使用的IO模型。  支持模型列表: 1、select 多路复用,在...
    nginx支持很多的网络IO模型,不同的平台支持的IO模型也有一定的区别,nginx正常情况下会根据平台自动选择有效的模型,
    也可以使用use命令指定需要使用的IO模型。

          支持模型列表:
    1、select   多路复用,在支持select的平台中会自动编译, --with-select_module和 --without-select_module可以手动的启用改IO模型或者禁止
    2、poll  多路复用,在支持poll的平台中会自动编译,  --with-poll_module和 --without-poll_module可以手动的启用改IO模型或者禁止
    3、kqueue 多路复用,在 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0, and macOS.这些平台使用
    4、epoll 多路复用,在linux2.6及以上内核可以使用,在一些较老版本的内核中,可以打epoll补丁使用
    5、/dev/poll 在 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+, and Tru64 UNIX 5.1A+平台可以使用
    6、eventport ,在  Solaris 10+ 平台使用,PS:由于一些已知的问题,建议 使用/dev/poll替代。
    展开全文
  • 四种常见网络IO模型

    2020-08-09 18:34:26
    网络IO模型一共有五种,同步阻塞IO、同步非阻塞IO、IO多路复用、信号驱动IO和异步IO。其中信号驱动IO并不常用,我们只要介绍其他四种。 首先我们需要了解一下网络IO的基本原理和一些基本的概念。 IO读写的基本原理 ...
  • Java IO:网络IO模型

    千次阅读 2016-02-18 17:25:13
    网络IO模型有5种,分别为:阻塞式IO,非阻塞式IO,IO复用,信号驱动式IO 和 异步IO。 一. 操作系统如何处理IO  Linux 会把所有的外部设备都看成一个文件来操作,对外部设备的操作可以看成是对文件的操作。我们对...
  • 五种网络IO模型

    2019-02-08 01:38:34
    网络IO模型总共有5种,分别是:阻塞IO、非阻塞IO、多路复用IO、信号驱动IO、异步IO 前四个都是同步IO,在内核数据copy到用户程序时都是阻塞的,而第五个则是异步的。 对网络IO来说,它会涉及两个部分,一个是用户...
  • 五种网络io模型

    千次阅读 2018-07-12 13:04:07
    由于最近再看nginx,其采用了优于apache的select网络io模型,所以稍微了解了下网络io的模型的基础知识。 首先,介绍几种常见的I/O模型及其区别,如下: blocking I/O nonblocking I/O I/O multiplexing (select ...
  • 网络IO模型 阻塞式I/O 默认情况下,所有的套接字的方法都是阻塞的,如上面的accept、recv。 对应的代码如下: package com.morris.bio; import java.io.BufferedReader; import java.io.IOException; import java....
  • 网络IO模型--事件模型

    2012-03-10 03:36:31
    编写高性能的网络应用程序,尤其是服务器端程序或进行web服务器的调优,需要深入理解网络IO模型。为了更好的理解IO模型,先介绍几个术语 1、术语  1)同步、异步:这里的同步、异步说法很诡异的,不用在上面纠结...
  • C++后台开发之网络IO模型

    千次阅读 2017-05-16 16:23:25
    为了解决网络IO中的问题,学者们提出了4种网络IO模型:①阻塞IO模型;②非阻塞IO模型;③多路IO复用模型;④异步IO模型。1.阻塞IO模型 在Linux中,默认情况下所有的socket都是阻塞的,阻塞和非阻塞的概念描述的是...
  • Linux下五种网络IO模型

    千次阅读 2019-05-24 16:45:03
    本文我们主要来了解一下Unix/Linux下5种网络IO模型:blocking IO, nonblocking IO, IO multiplexing, signal driven IO, asynchronous IO的基本原理,更好的理解在高级语言中的异步编程,一起来看看吧,希望对大家...
  • 网络IO模型和select/epoll对比

    千次阅读 2018-06-27 09:05:07
    下面都是以网络读数据为例【2阶段网络IO】第一阶段:等待数据 wait for data第二阶段:从内核复制数据到用户 copy data from kernel to user下面是5种网络IO模型【阻塞blocking IO】两阶段全程阻塞recvfrom -&...
  • 转载和积累系列 - 网络IO模型

    千次阅读 2014-12-18 21:26:41
    网络IO模型介绍 常见的IO模型有以下5种: 1. 阻塞式IO (blocking IO) 2.无阻塞式IO (nonblocking IO) 3.IO多路复用 (IO multiplexing) 4. 信号驱动 (signal driven IO) 5. 异步IO (asynchronous IO) ...
  • 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,就认为asynchronous IO和non...
  • Linux网络IO模型

    千次阅读 2018-10-30 11:15:45
    看上面的例子,我们再来关注Linux网络IO模型,然后结合这个例子去理解。 Linux网络IO模型 Unix提供了五种IO模式,分别是: 阻塞IO 非阻塞IO IO复用 信号驱动IO 异步IO 在...
  • 5种网络IO模型

    万次阅读 多人点赞 2015-04-10 10:39:07
    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,就认为asynchronous IO和non...
  • 5种网络IO模型、Reactor、Proactor

    千次阅读 2013-09-10 14:48:45
    网络IO模型包括:阻塞I/O、非阻塞I/O、I/O复用(select和poll)、信号驱动I/O(SIGNO)、异步I/O(Posix的aio_系列函数) 一、同步IO模型 1.1 阻塞I/O 1.2 非阻塞I/O 1.3 I/O复用(select和poll) 1.4 信号驱动I/O...
  • 首先我们从他们所占有的平台来看 select 是跨平台的 windows、...五种网络IO模型: 同步阻塞IO:当用户线程调用请求(如调用read(),write(),listen()等接口),内核就会等待数据的到来,数据到来时实行数据拷贝,...
  • 理解5种网络IO模型

    2015-07-17 15:24:07
    我觉得要理解5种网络模型,第一看懂Stevens的那张图 第二用身边的一件例子来理解它 然后对于Stevens的图我就不过多解释了,下面我介绍下我怎么用生活中的例子来理解他的,故事的起因源自一次酒店洗衣服 然后我...
  • Netty系列---网络IO模型

    千次阅读 2019-10-24 19:36:14
    网络IO的本质就是socket流的读取,通常一次IO读操作会涉及到两个对象和两个阶段。 两个对象分别是: 用户进程(线程)Process(Thread) 内核对象 Kernel 两个阶段: 等待流数据准备(wating for the data to be ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 183,352
精华内容 73,340
关键字:

网络io模型