精华内容
下载资源
问答
  • IO复用

    2019-09-18 05:36:35
    IO复用:MariaDBPerconaDBweb :Nginx , LNMP, Memcached ,tomcat ,varnishwww.nginx.org 官方站点 Nginx pronounced engine-xHTTP服务器反向代理 :reverse proxy反向代理的协议 httpmailnetcraft 网站 web市场占有...

    IO复用:
    MariaDB
    PerconaDB
    web :Nginx , LNMP, Memcached ,tomcat ,varnish
    www.nginx.org 官方站点

    Nginx pronounced engine-x
    HTTP服务器
    反向代理 :reverse proxy
    反向代理的协议
    http
    mail
    IO复用
    netcraft 网站 web市场占有率

    IO复用

    Nginx优势 :
    高性能
    稳定性
    丰富的特性
    简单配置
    低资源消耗

    多进程模型
    进程切换
    阻塞状态 不可中断睡眠
    DMA 直接内存访问

    C10K
    单进程 :阻塞
    多进程 :每个进程响应一个请求
    进程量大。进程切换次数过多
    每个进程的地址空间是独立,很多空间是重复的数据,所以内存使用效率较低
    线程 :thread, Light Weight Process, LWP
    每个线程响应一个请求
    线程依然需要切换,切换较之进程轻量级
    同一个进程的线程可以共享进程的诸多资源,比如打开的文件
    对内存的需求较之进程略有下降
    快速切换时会带来线程抖动
    忙等 :自旋锁 Spin lock
    闲等

    多进程多线程模型:
    多线程:n个请求
    一个线程响应多个请求
    select(1024)
    AIO :异步IO

    同步通信
    异步通信

    多路IO,IO复用
    IO复用
    IO Models :
    IO复用
    阻塞IO
    非阻塞IO
    IO复用
    信号驱动IO
    异步IO

    同步IO和异步IO
    IO复用
    异步阻塞IO 又称为IO复用
    阻塞IO具体模型详解:
    IO复用
    非阻塞IO具体模型详解:
    IO复用

    IO复用具体模型详解:
    IO复用

    事件驱动IO:水平触发,边缘触发
    数据准备完成后向进程通知
    5种模型对比 :
    IO复用
    epoll
    /dev/poll
    kqueue

    mmap:内存映射
    异步IO 实现起来比较复杂

    IO:网络IO和磁盘IO
    httpd :
    MPM
    prefork :一个进程响应一个请求 ,1024
    worker :一个线程响应一个请求,多线程,一个进程生成多个线程
    event :基于事件驱动

    Nginx 做反向代理
    程序有局部性,数据有局部性
    CDN 内容分发网络 依赖于智能DNS 内容路由 缓存路由
    hadoop 大数据分析 异步结构
    NoSQL 大量写操作时使用
    模块化 架构师 拓展起来

    展开全文
  • 1 select实现IO复用的思路02 下面的都是伪代码,主要讲究思路。 1)lfd=socket()。 2)bind()。 3)listen()。 4)将lfd添加到select的读集合用于传入,借助内核帮我们监听事件,而不直接调用accept函数监听。为了...

    1 select实现IO复用的思路02

    下面的都是伪代码,主要讲究思路。

    • 1)lfd=socket()。
    • 2)bind()。
    • 3)listen()。
    • 4)将lfd添加到select的读集合用于传入,借助内核帮我们监听事件,而不直接调用accept函数监听。为了方便我们只需要添加读集合即可。
    fd_Set rset,allset;//rset为读监听的集合
    FD_ZERO(&rset);
    FD_SET(lfd,&rset);
    
    • 5)调用select函数实现IO复用。
    int ret = select(lfd+1, &rset, NULL, NULL, NULL);//注意,当select执行完毕rset变成传出参数了
    
    • 6)然后将内核监听到的请求即请求连接(lfd触发),请求通信(cfd触发)进行处理。即利用select传出的参数rset文件描述符集合进行处理,因为rset里面是满足lfd,cfd的请求。如果有新客户端请求连接,那么lfd将在rset中,若客户端请求通信,那么cfd将在rset中,否则不在。这里需要注意,ret返回的总事件数只是能让你快速判断是否有请求事件发生,或者判断错误,实际作用一般就是这两个。
      select的所有的操作都是基于rset文件描述符集合来处理。
    	//1 select的返回值一般用于判断错误
    	if (ret < 0)
    		perr_exit("select error");
    		
    	//2 判断客户端是否有新的请求建立连接
    	if (FD_ISSET(listenfd, &rset)) { 
    		/* new client connection */
    		connfd = accept();
    		//其它处理...
    	}
    	//3 遍历所有文件描述符,依次查看描述符是否在rset出现,若出现,说明客户端有对应请求。
    	//即处理cfd通信描述符
    	for(i = lfd + 1; i<=最大文件描述符数;i++){
    		if(FD_ISSET(i, &rset)){
    			//读写操作
    		}
    	}
    

    以上就是select实现IO复用的思路,select不建议深入。

    展开全文
  • 在网络编程的过程中,一直不太清晰的几个问题: 1、我已经知道一个服务端socket的...该如何选取使用多线程+非阻塞式(对应每一个链接都要开辟一个线程)还是非阻塞+io复用模式? 2、socket编程过程中,setsocketop...

    在网络编程的过程中,一直不太清晰的几个问题:

    1、我已经知道一个服务端socket的产生过程为socket()->bind()->listen()->accept(),但是服务端是如何高效的与多个客户端连接这个问题一直没有很清晰的流程?该如何选取使用多线程+非阻塞式(对应每一个链接都要开辟一个线程)还是非阻塞+io复用模式?

    2、socket编程过程中,setsocketopt()函数的主要功能作用是什么?select()的作用是什么(为何能实现多路io复用)?FD_ISSET()函数的作用又是什么?

    3、怎么样才能比较完美的实现tcp应用层的拼包处理?发送和接受是否需要通过队列在不同的线程中去处理?

    诸如以上的问题,大部分是由于自己对于socket网络编程的理解不够深入导致,下面尽我所能将我理解的,综合网络上的博客进行记录整理。


    在linux系统的socket编程中,常用系统函数主要在<sys/types.h>、<sys/socket.h>、<unistd.h>、<arpa/inet.h>中,下面依次介绍几个重要的系统函数:​​

    A、socket()

    int socket(int domain, int type, int protocol);

    这个操作类似于打开文件操作,返回socket的socket描述符。

    参数:

    domain:协议域,又称为协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL、AF_ROUTE。协议族决定了socket的地址类型,通信时采用与其相符的地址,AF_INET用ipv4地址(32位)和16位端口号的组合

    type:指定socket类型,常用的有SOCK_STREAMSOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET,前两个分别对应TCP和UDP类型的socket

    protocol:指定协议,常用有IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC,协议和socket的类型要匹配。0会选择type对应的默认类型。

    示例:

    m_listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


    B、bind()

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    把一个地址族的特定地址指定给socket,而不是由系统随机分配.

    参数:

    sockfd:socket描述符,socket()函数返回的int值

    addr:一个地址结构体的const指针,指向要绑定给sockfd的地址,结构体的结构和地址协议相符。

    如ipv4的地对应的

    
    struct sockaddr_in {
       sa_family_t    sin_family; /*地址族: AF_INET */
       in_port_t      sin_port;   /*网络字节序的端口号 */
       struct in_addr sin_addr;   /*internet 地址 */
    };
     /* Internet 地址. */
    struct in_addr {
       uint32_t       s_addr;     /* 网络字节序的地址 */
    
    

    应该注意使用htol,htos函数将主机字节顺序转换为网络字节顺序,避免潜在的错误。

    示例:

    socklen_t  addrlen=sizeof(struct sockaddr_in);  
    bzero(&ser_addr,addrlen);  
    ser_addr.sin_family=AF_INET;  
    ser_addr.sin_addr.s_addr=htonl(INADDR_ANY);  
    ser_addr.sin_port=htons(SERVER_PORT);  
        if(bind(ser_sockfd,(struct sockaddr*)&ser_addr,sizeof(struct sockaddr_in))<0){ /*绑定失败 */  
                fprintf(stderr,"Bind Error:%s\n",strerror(errno));  
                exit(1);  
        } 
    

     

    C、setsocketopt()

    【getsockopt/setsockopt系统调用】  
       
    功能描述:
            获取或者设置与某个套接字关联的选 项。选项可能存在于多层协议中,它们总会出现在最上面的套接字层。当操作套接字选项时,选项位于的层和选项的名称必须给出。为了操作套接字层的选项,应该 将层的值指定为SOL_SOCKET。为了操作其它层的选项,控制选项的合适协议号必须给出。例如,为了表示一个选项由TCP协议解析,层应该设定为协议 号TCP。


    用法:
    #include <sys/types.h>
    #include <sys/socket.h>

    int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);

    int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);

    参数:  
    sock:将要被设置或者获取选项的套接字。
    level:选项所在的协议层。
    optname:需要访问的选项名。
    optval:对于getsockopt(),指向返回选项值的缓冲。对于setsockopt(),指向包含新选项值的缓冲。
    optlen:对于getsockopt(),作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。对于setsockopt(),现选项的长度。


    返回说明:  


    成功执行时,返回0。失败返回-1,errno被设为以下的某个值  
    EBADF:sock不是有效的文件描述词
    EFAULT:optval指向的内存并非有效的进程空间
    EINVAL:在调用setsockopt()时,optlen无效
    ENOPROTOOPT:指定的协议层不能识别选项
    ENOTSOCK:sock描述的不是套接字


    参数详细说明:

    level指定控制套接字的层次.可以取三种值:
    1)SOL_SOCKET:通用套接字选项.
    2)IPPROTO_IP:IP选项.
    3)IPPROTO_TCP:TCP选项. 
    optname指定控制的方式(选项的名称),我们下面详细解释 

    optval获得或者是设置套接字选项.根据选项名称的数据类型进行转换 


    选项名称        说明                  数据类型
    ========================================================================
                SOL_SOCKET
    ------------------------------------------------------------------------
    SO_BROADCAST      允许发送广播数据            int
    SO_DEBUG        允许调试                int
    SO_DONTROUTE      不查找路由               int
    SO_ERROR        获得套接字错误             int
    SO_KEEPALIVE      保持连接                int
    SO_LINGER        延迟关闭连接              struct linger
    SO_OOBINLINE      带外数据放入正常数据流         int
    SO_RCVBUF        接收缓冲区大小             int
    SO_SNDBUF        发送缓冲区大小             int
    SO_RCVLOWAT       接收缓冲区下限             int
    SO_SNDLOWAT       发送缓冲区下限             int
    SO_RCVTIMEO       接收超时                struct timeval
    SO_SNDTIMEO       发送超时                struct timeval
    SO_REUSERADDR      允许重用本地地址和端口         int
    SO_TYPE         获得套接字类型             int
    SO_BSDCOMPAT      与BSD系统兼容              int
    ========================================================================
                IPPROTO_IP
    ------------------------------------------------------------------------
    IP_HDRINCL       在数据包中包含IP首部          int
    IP_OPTINOS       IP首部选项               int
    IP_TOS         服务类型
    IP_TTL         生存时间                int
    ========================================================================
                IPPRO_TCP
    ------------------------------------------------------------------------
    TCP_MAXSEG       TCP最大数据段的大小           int
    TCP_NODELAY       不使用Nagle算法             int
    ========================================================================

    返回说明:  
    成功执行时,返回0。失败返回-1,errno被设为以下的某个值  
    EBADF:sock不是有效的文件描述词
    EFAULT:optval指向的内存并非有效的进程空间
    EINVAL:在调用setsockopt()时,optlen无效
    ENOPROTOOPT:指定的协议层不能识别选项
    ENOTSOCK:sock描述的不是套接字

    SO_RCVBUF和SO_SNDBUF每个套接口都有一个发送缓冲区和一个接收缓冲区,使用这两个套接口选项可以改变缺省缓冲区大小。

    // 接收缓冲区
    int nRecvBuf=32*1024;         //设置为32K
    setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));


    //发送缓冲区
    int nSendBuf=32*1024;//设置为32K
    setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

    注意:

            当设置TCP套接口接收缓冲区的大小时,函数调用顺序是很重要的,因为TCP的窗口规模选项是在建立连接时用SYN与对方互换得到的。对于客户,O_RCVBUF选项必须在connect之前设置;对于服务器,SO_RCVBUF选项必须在listen前设置。

    结合原理说明:

            1.每个套接口都有一个发送缓冲区和一个接收缓冲区。 接收缓冲区被TCP和UDP用来将接收到的数据一直保存到由应用进程来读。 TCP:TCP通告另一端的窗口大小。 TCP套接口接收缓冲区不可能溢出,因为对方不允许发出超过所通告窗口大小的数据。 这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接 收方TCP将丢弃它。 UDP:当接收到的数据报装不进套接口接收缓冲区时,此数据报就被丢弃。UDP是没有流量控制的;快的发送者可以很容易地就淹没慢的接收者,导致接收方的UDP丢弃数据报。
            2.我们经常听说tcp协议的三次握手,但三次握手到底是什么,其细节是什么,为什么要这么做呢?
            第一次:客户端发送连接请求给服务器,服务器接收;
            第二次:服务器返回给客户端一个确认码,附带一个从服务器到客户端的连接请求,客户机接收,确认客户端到服务器的连接.
            第三次:客户机返回服务器上次发送请求的确认码,服务器接收,确认服务器到客户端的连接.
            我们可以看到:
            1. tcp的每个连接都需要确认.
            2. 客户端到服务器和服务器到客户端的连接是独立的.
            我们再想想tcp协议的特点:连接的,可靠的,全双工的,实际上tcp的三次握手正是为了保证这些特性的实现.


            3.setsockopt的用法

    1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:
    BOOL bReuseaddr=TRUE;
    setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));


    2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历TIME_WAIT的过程:
    BOOL bDontLinger = FALSE;
    setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));


    3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
    int nNetTimeout=1000;//1秒
    //发送时限
    setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
    //接收时限
    setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));


    4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节
    (异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据
    和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:
    // 接收缓冲区
    int nRecvBuf=32*1024;//设置为32K
    setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
    //发送缓冲区
    int nSendBuf=32*1024;//设置为32K
    setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));


    5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响
    程序的性能:
    int nZero=0;
    setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));


    6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
    int nZero=0;
    setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));


    7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
    BOOL bBroadcast=TRUE;
    setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));


    8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的作用,在阻塞的函数调用中作用不大)
    BOOL bConditionalAccept=TRUE;
    setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL));


    9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体应用的要求(即让没发完的数据发送出去后在关闭socket)?
    struct linger {
    u_short l_onoff;
    u_short l_linger;
    };
    linger m_sLinger;
    m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
    // 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
    m_sLinger.l_linger=5;//(容许逗留的时间为5秒)
    setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));


    说明:以下内容转载自博客http://blog.csdn.net/wqc_csdn/article/details/51583901,侵删

    在之前我们实现的并发服务端时通过创建多个进程来实现的,这种并实现并发的方式简单方便,但是进程的创建和销毁是很消耗系统资源的,在访问量大时服务器很容易出现资源不够用的情况。除此之外,由于每个进程有独立的内存空间,所以进程间的通讯也相对比较复杂。因此我们可以考虑通过另一种方式来实现服务端的并发服务——IO复用。

    复用:

    复用在通讯领域很常见,一般常见”频分复用”,”时分复用”等名词。其实复用就是在一个通信频道内传递多个数据(信号)的技术。以频分复用为例:其实就是在一个通信信道内,发送端通过把信息加载在不同频率的波段上进行发送,而接受端在接受到波时通过滤波装置把各中频率的波进行分离,以此达到提高通信信道利用率的目的。

    IO复用:

    IO复用其实也是通过对IO描述符的复用来减少进程的创建,使得服务端始终只有一个进程,从而节省了系统资源,提高效率。


    select()函数是最具有代表性的实现复用服务端的方法,它可以将多个文件描述符集中到一起进行统一监视,当监视到有文件描述符需要输入或者是输出时就选择该接口进行通讯,通讯完成之后就回到之前监视的状态。

    监视内容:是否存在套接字接受数据?无需阻塞传输数据的套接字有哪些?哪些套接字发生了异常?

    int select(int maxfd,fd_set *read_set, *write_set,fd_set *except_set, const struct timeval *timeout)选择描述符进行通讯:

    • maxfd(监视数量):监视对象文件描述符数量

    • read_set(读取文件描述符集合的地址):将所有关注”是否存在待读取数据”的文件描述符注册到fd_set集合中,并传递地址值。也就是说select()函数会监视这个集合里边的文件描述符是是否有待读取的数据,没有要监听的描述符时传0

    • write_set(写入文件描述符集合的地址):将所有关注”是否可传输无阻塞数据”的文件描述符注册到fd_set集合中,并传递地址值。也就是说select()函数会监视这个集合里边的文件描述符是否能发送无阻塞数据,没有要监听的描述符时传0

    • except_set(发生异常文件描述符集合的地址):将所有关注”是否可发生异常”的文件描述符注册到fd_set集合中,并传递地址值。也就是说select()函数会监视这个集合里边的文件描述符是否发生异常,没有要监听的描述符时传0

    • timeout(超时):为防止无限进入阻塞状态,设置一个超时信息

    发生错误时返回-1,超时时返回0,当所关注的事件发生时,返回所发生事件的文件描述符数量

    展开全文
  • IO模型和IO复用

    2020-04-15 14:41:19
    文章目录五中网络IO模型阻塞IO非阻塞IO复用IO异步IO信号驱动IOIO复用函数调用selectpollepollepoll的工作模式LT模式ET模式 五中网络IO模型 IO的执行分为等待数据和拷贝数据两个阶段。 阻塞IO 指IO操作彻底完成后才...

    五中网络IO模型

    IO的执行分为等待数据和拷贝数据两个阶段。

    阻塞IO

    指IO操作彻底完成后才返回用户空间。IO执行的数据等待和数据拷贝两个阶段都被阻塞。几乎所有的IO接口都是阻塞型的。改进方案:使用多线程、多进程、线程池、连接池。

    非阻塞IO

    指IO操作被调用后立即返回给用户一个状态值,不需要等到IO操作彻底完成才返回。在数据准备阶段,用户进程不被阻塞,但是需要不断轮询,询问内核数据是否准备好。

    复用IO

    是指使用select、poll、epoll等函数调用来同时监控多个套接字描述符的操作。可以等待多个套接字中的任何一个变为可读,就可以通知用户执行数据拷贝。这一函数调用过程是被阻塞的,当某一个套接字可读时返回,之后再使用recvfrom把数据从内核复制到进程空间。
    他可以让单个进程具有处理多个IO事件的能力,又被称为事件驱动IO(Event Driven IO)。

    异步IO

    应用进程执行aio_read系统调用之后会立即返回,应用进程可以继续执行,不会被阻塞,内核在所有操作完成之后向应用进程发送信号。

    信号驱动IO

    应用进程使用sigaction 系统调用,内核立即返回,应用进程可以继续执行,也就是说数据准备阶段应用进程是非阻塞的。当数据准备好之后,内核向应用进程发送SIGIO信号,进程收到信号之后再调用recvfrom将数据从内核复制到应用进程中。
    相比于非阻塞IO,信号驱动IO的CPU利用率更高。
    相比于异步IO,信号驱动IO通知应用进程可以开始IO,而异步IO是通知应用进程IO完成。
    在这里插入图片描述

    IO复用函数调用

    select、poll、epoll都是IO复用的具体实现,他们三者出现的时间顺序一次向后。

    select

    int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    

    有三种类型的描述符类型:readset、writeset、exceptset,分别对应读、写、异常条件的描述符集合。fd_set使用数组实现,数组大小使用FD_SETSIZE定义,
    timeout为超时参数,调用select会一直阻塞直到有描述符的时间到达或者超时。成功调用返回值大于0,出错返回结果为-1,超时返回0。

    poll

    int poll(struct pollfd *fds, unsigned int nfds, int timeout);
    

    pollfd使用链表实现。
    select和poll的比较,二者基本相同,但实现细节有所不同:
    -功能
    - select会修改描述符,但poll不会;
    - select的描述符类型使用数组实现,FD_SETSIZE默认1024,因此只能监听1024个描述符。如果需要监听更多,需要修改FD_SETSIZE后重新编译;而poll描述符类型使用链表实现,没有数量限制。
    - poll提供更多的时间类型,并且对描述符服用利用率更高。
    - 如果一个线程对某描述符调用了select或者poll,但另一线程关闭了该描述符,会导致结果不确定。

    • 速度
      • 都比较慢,需要将全部描述符从应用进程缓冲区复制到内核缓冲区。
      • 返回结果中没有申明哪些描述符准备好,如果返回值大于零,应用进程需要轮询扎到IO完成的描述符。
    • 可移植性
      • 几乎所有系统支持select,但比较新的系统才支持poll。

    epoll

    int epoll_create(int size);
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    

    epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵
    红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事
    件完成的描述符。
    从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获
    得事件完成的描述符。

    epoll只适用于Linux OS。
    epoll比select和poll更加灵活,没有进程描述符数量的限制。
    epoll对多线程更友好,一个线程调用epoll_wait() 另一个线程关闭了同一个描述符也不会产生像 select 和
    poll 的不确定情况。

    epoll的工作模式

    LT模式

    当epoll_wait函数检测到描述符时间到达,将此事件通知给进程,进程可以不立即处理该事件,下次调用epoll_wait 会再次通知该进程,这是默认的一种工作模式。

    ET模式

    和LT模式不同的是,通知进程后必须立即处理事件,下次调用epoll_wait函数将不会再得到事件到达的通知。这种模式减少了epoll事件触发的次数,因此效率要高。只支持No-blocking,避免由于一个文件句柄的阻塞读、写操作把处理多个文件描述符的任务饿死。

    展开全文
  • 网络IO 多路IO复用 select poll epoll 为什么要用多路io复用呢? 如果不用多路io复用,可以开辟多个线程,或者一个线程循环的去读取每个io的数据,这样的开销是非常的大的,而且会大大的影响系统的性能,因此...
  • 网络IO 多路IO复用 select poll epoll epoll用于多路io复用,具体是如何实现的? 内部使用 epoll_create() epoll_ctl() epoll_wait() 3个函数来实现 多路io复用 epoll模型的底层是用红黑树来处理的 ...
  • 在之前我们实现的并发服务端时通过床将多个...因此我们可以考虑通过另一种方式来实现服务端的并发服务——IO复用。复用:复用在通讯领域很常见,一般常见”频分复用”,”时分复用”等名词。其实复用就是在一个通信频
  • LinuxIo复用

    2020-01-14 15:19:40
    LinuxIO复用 标准流和流功能 stdin 0 scanf stdout 1 printf stderr 2 write(目的,源,length) write(stdout,inet_ntoa(in.sin_addr),sizeof(in.sin_addr)) printf read(0) scanf write read fd=open("/dev/tty")...
  • 转载:IO复用\阻塞IO\非阻塞IO\同步IO\异步IO 一、 什么是IO复用? 它是内核提供的一种同时监控多个文件描述符状态改变的一种能力;例如当进程需要操作多个IO相关描述符时(例如服务器程序要同时查看监听socket和...
  • 主要介绍了Java IO复用的相关知识,非常不错,具有参考借鉴价值,需要的的朋友参考下吧
  • 下面本文先从同步和异步的概念 说起,然后接着阐述了阻塞和非阻塞的区别,接着介绍了阻塞IO和非阻塞IO的区别,然后介绍了同步IO和异步IO的区别,接下来介绍了5种IO模型,最后 介绍了两种和高性能IO设计相关的设计...
  • 多路IO复用

    2018-02-04 10:10:26
    本文,记录多路IO复用的使用。 顺序 接口示例(CS模型示例) IO多路复用之select总结,链接IO多路复用之epoll总结,链接 应用模型(事件驱动) 使用事件驱动模型实现高效稳定的网络服务器程序,链接 ...
  • 在一个IO操作过程中,以read为例,会涉及到两个过程: 1.等待数据准备好; 2.将数据从内核拷贝到进程中 这两个阶段是否发生阻塞,将产生不同的效果。 堵塞IO: 进程在请求read阻塞io的数据时,操作需要彻底完成后才...
  • 为什么要io复用

    千次阅读 2015-11-07 15:52:58
    里面有个重要的概念是 io复用.  1. 为什么需要io复用 why ?  2. io复用 怎么改进这个问题的? 1.为什么需要io复用 why ? 先理解下5种io模型. 传统两种阻塞式轮询的问题.都是一个线程监听端口的连接请求,然后产生...
  • IO复用\阻塞IO\非阻塞IO\同步IO\异步IO 本文是对《UNIX网络编程卷1》第6章的总结。 一、 什么是IO复用? 它是内核提供的一种同时监控多个文件描述符状态改变的一种能力;例如当进程需要操作多个IO相关描述符时...
  • php socket select IO复用

    千次阅读 2017-12-04 11:39:51
    此篇博客是接着上篇php socekt阻塞模型PHP代码(php socket IO阻塞方式的Server/Client)的进阶,IO阻塞模型...此片为linux的IO操作的5大模型第三种模型:IO复用,而IO复用又有多种方式实现,常见的如select、poll、epoll
  • IO模型浅析-阻塞、非阻塞、IO复用、信号驱动、异步IO、同步IO 原文地址 IO模型浅析-阻塞、非阻塞、IO复用、信号驱动、异步IO、同步IO 正文 IO模型 在《UNIX网络变成卷1:套接字联网API》这本书中,提到了五种I/O模型...
  • 13 IO复用之select函数

    2019-03-09 11:25:16
    但是IO复用可以在同时处理多个socket的IO请求. 而且IO复用与线程连用是最常见的搭配. 本节介绍IO多路复用select函数. 函数原型 #include &lt;sys/types.h&gt; #include &lt;sys/times.h&gt; #...
  • 下面小编就为大家带来一篇IO复用之select poll epoll的总结(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 线程怎么与IO复用联系起来, IO复用中创建线程? 还是线程中IO复用? 这个问题用在进程也是一样的. 其实两种方式都可以. 本节采用在 IO复用中创建线程, 接下来就来看看具体怎么实现的吧. epoll 的EPOLLONESHOT事件 还...
  • <网络编程>IO复用

    2019-04-16 23:24:00
    IO复用 IO复用是一种机制,一个进程可以监听多个描述符,一旦某个描述符就绪(读就绪和写就绪),能够同志程序进行相应的读写操作。 目前支持I/O复用的系统调用有select,poll,pselect,epoll,本质上...
  • 常见的IO复用场景

    2020-12-06 15:03:30
    在网络程序中比较常见的要使用到IO复用的场景如下: 客户端程序要同时处理多个socket,如非阻塞connect技术 客户端程序要同时处理用户输入和网络连接。比如聊天室程序。 TCP服务器要同时处理监听socket和连接socket...
  • 三种io复用的总结

    2019-08-09 19:46:07
    io复用的作用是能使程序同时监听多个文件描述符; 一般在下面几种情况下要用到io复用: 客户端程序要同时处理多个socket。 客户端程序要同时处理用户输人和网络连接。 TCP服务器要同时处理监听socket和连接...
  •   Linux系统的3组IO复用系统调用(参考select()和poll()、epoll机制)都带有超时参数timeout,即它们不单能处理IO事件和信号(统一事件源),还可以处理定时器超时事件。但是需要注意两点:   (1)该系统调用既然能...
  • go实现Kqueue和IO复用

    2020-09-02 18:52:18
    常见的io复用有select、poll、epoll、kqueue等。其中epoll为Linux系统独有,kqueue则在众多unix系统中存在,我们这里选择Kqueue进行切入主要是方便mac上IDE即时编译调试,其原理与epoll类似。 Kqueue参数概览 go语言...
  • 并发与io复用

    2014-03-21 15:28:05
    epool poll 多并发的io复用

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,045
精华内容 4,818
关键字:

io复用