I/O多路转接之epoll

I/O多路转接select/poll/epoll模型 I/O多路转接包含(select/poll/epoll) 1、I/O多路转接select 系统提供select函数实现多路复用的输入输出模型 select系统调用让程序监视多个文件描述符的状态变化,程序会暂停到select这里等待,直到被监视的文件描述符发送了状态变化 #include<sys/select.h> //头文件 int select (int nfds, ... 阅读详情
I/O多路转接之epoll
epoll:处理大批量句柄而做了改进的poll。

工作模式:
1、边缘触发(ET)当收到数据的时候,通知你读取数据。当你没有读取的时候,不会通知你,可能造成数据丢失。当你来读取数据的时候,就应该对这次的数据读取完毕。
   LT(level triggered)是epoll缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。 传统的select/poll都是这种模型的代表.

2、水平触发(LT)读取数据的时候没有读取继续通知你来读取。
   ET(edge-triggered)是高速工作方式,只支持no-block socket,它效率要比LT更高。ET与LT的区别在于,当一个新的事件到来时,ET模式下当然可以从epoll_wait调用中获取到这个事件,可是如果这次没有把这个事件对应的套接字缓冲区处理完,在这个套接字中没有新的事件再次到来时,在ET模式下是无法再次从epoll_wait调用中获取这个事件的。而LT模式正好相反,只要一个事件对应的套接字缓冲区还有数据,就总能从epoll_wait中获取这个事件。 因此,LT模式下开发基于epoll的应用要简单些,不太容易出错。而在ET模式下事件发生时,如果没有彻底地将缓冲区数据处理完,则会导致缓冲区中的用户请求得不到响应。

三个系统调用:epoll_create,epoll_ctl,epoll_wait。

创建一个epoll句柄,size参数是被忽略的。
注意:当创建好epoll句柄后,他就会占用一个fd值,所以在用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

epoll的事件注册函数,它不同于select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。
    第一个参数是epoll_create()的返回值。
    第二个参数表示动作,用三个宏来表示:
EPOLL_CTL_ADD:注册新的fd到epfd中;
      EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删除一个fd;
    第三个参数是需要监听的fd。
    第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:

     events可以是以下几个宏的集合:
     EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
     EPOLLOUT:表示对应的文件描述符可以写;
     EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
     EPOLLERR:表示对应的文件描述符发生错误;
     EPOLLHUP:表示对应的文件描述符被挂断;
     EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
     EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

  收集在epoll监控的事件中已经发送的事件。参数events是分配好的epoll_event结构体数组, epoll将会把发生的事件赋值到events数组中(events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存)。maxevents告诉内核这个 events有多大,这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。如果函数调用成功,返回对应I/O上已准备好的文件描述符数目,如返回0表示已超时。

epoll工作原理

1)调用epoll_create时,做了以下事情:
   内核帮我们在epoll文件系统里建了个file结点;
   在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket;
   建立一个list链表,用于存储准备就绪的事件。
2)调用epoll_ctl时,做了以下事情:
   把socket放到epoll文件系统里file对象对应的红黑树上;
   给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。
3)调用epoll_wait时,做了以下事情:
   观察list链表里有没有数据。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。而且,通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已。

总结如下:
  一颗红黑树,一张准备就绪句柄链表,少量的内核cache,解决了大并发下的socket处理问题。
  执行epoll_create时,创建了红黑树和就绪链表; 
  执行epoll_ctl时,如果增加socket句柄,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断事件来临时向 准备就绪链表中插入数据; 
  执行epoll_wait时立刻返回准备就绪链表里的数据即可。

在epoll ET模式中,为何fd必须要设置为非阻塞?
   ET(边缘触发)数据就绪只会通知一次,也就是说,如果要使用ET模式,当数据就绪时, 需要一直read,直到出错或完成为止。但倘若当前fd为阻塞(默认),那么在当读完缓冲区的数据时,如果对端并没有关闭写端,那么该read函数会一直阻塞,影响其他fd以及后续逻 辑!所以此时将该fd设置为非阻塞,当没有数据的时候,read虽然读取不到任何内容,但是肯定不会被hang住,那么此时,说明缓冲区数据已经读取完毕,需要继续处理后续逻辑(读取其他fd或者进入wait)。

epoll的优点:
1、本身没有最大并发连接的限制,仅受系统中进程能打开的最大文件数目限制;
2、I/O效率不随fd数量的1增加而线性下降
3、使用mmap加速内核与用户空间的消息传递
4、内核微调:这一点其实不算epoll的优点了,而是整个linux平台的优点。也许你可以怀疑linux平台,但是你无法回避linux平台赋予你微调内核的能力。比如,内核TCP/IP协议栈使用内存池管理sk_buff结构,那么可以在运行时期动态调整这个内存pool(skb_head_pool)的大小--- 通过echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函数的第2个参数(TCP完成3次握手的数据包队列长度),也可以根据你平台内存大小动态调整。更甚至在一个数据包面数目巨大但同时每个数据包本身大小却很小的特殊系统上尝试最新的NAPI网卡驱动架构。
 
epoll的缺点:
1、跨平台性不够强,只能工作在linux平台下
2、使用复杂一些,但相比IOCP,增加的一点复杂度基本上达到了IOCP的并发量和性能,而复杂度远远小于IOCP.
3、相比于IOCP来说,对多核/多线程的支持不够好,在性能要求比较苛刻的情况下不然IOCP。

epoll测试代码:
/**************************************************************************
    >file name:my_epoll.c
    >author:Comedly
    >create time:2016-8-9
**************************************************************************/

#include<stdio.h>
#include<sys/epoll.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>
#include<unistd.h>

//static void my_read(int epfd,int fd,char *buf,int len)
//{
//    int rs = 1;
//    while(rs)
//    {
//        ssize_t size = recv(fd,buf,len,0);
//        if(size < 0)
//        {
//            if(errno = EAGAIN)
//            {
//                break;
//            }
//            else
//            {
//                perror("recv");
//                return 9;
//            }
//        }
//        else if(size == 0)
//        {
//            //表示对端的sock已经正常关闭
//            printf("client close....\n");
//            struct epoll_event ev;
//            epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);
//            close(fd);
//            break;
//        }
//        else
//        {
//            buf[size - 1] = '\0';
//            printf("client # %s\n",buf);
//            if(size == len)
//            {
//                rs = 1;
//            }
//            else
//            {
//                rs = 0;
//            }
//        }
//    }
//}

//static void my_write(int fd,char *buf,int len)
//{
//    int ws = 1;
//    while(ws)
//    {
//        ssize_t size = send(fd,buf,len,0);
//        if(size < 0)
//        {
//            //缓冲区已满,延时重试
//            if(errno == EAGAIN)
//            {
//                usleep(1000);
//                continue;
//            }
//            if(errno == EINTR)
//            {
//                return -1;
//            }
//        }
//        if(size == len)
//        {
//            continue;
//        }
//        len -= size;
//        buf += size;
//    }
//}

ssize_t my_read(int fd,char buf[])
{
    int ret = 0;
    int total = 0;
    while((ret = read(fd,buf+total,sizeof(buf)-total)) && errno != EAGAIN)
    {
        total +=ret;
    }
    buf[total] = '\0';
    return total;
}

static void set_no_block(int fd)
{
    //先得到之前的状态,在之前的状态上加入新状态,将其设置为非阻塞。
    int before = fcntl(fd,F_GETFL);
    fcntl(fd,F_SETFL,before|O_NONBLOCK);
}

static int startup(const char *ip,int port)
{
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock < 0 )
    {
        perror("socket");
        return 2;
    }

    int opt = 1;
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(port);
    local.sin_addr.s_addr = inet_addr(ip);

    if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
    {
        perror("bind");
        return 3;
    }
    if(listen(sock,5) < 0)
    {
        perror("listen");
        return 4;
    }
    return sock;
}

static void usage(const char* proc)
{
    printf("%s [ip][port]\n",proc);
}

int main(int argc,char* argv[])
{
    if(argc != 3)
    {
        usage(argv[0]);
        return 1;
    }
    int listen_sock = startup(argv[1],atoi(argv[2]));
    int epfd = epoll_create(128);
    if(epfd < 0)
    {
        perror("epoll_create");
        return 5;
    }
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = listen_sock;
    if(epoll_ctl(epfd,EPOLL_CTL_ADD,listen_sock,&ev) < 0)
    {
        perror("epoll_ctl");
        return 6;
    }
    struct epoll_event evs[128];
    int len = sizeof(evs)/sizeof(evs[0]);
    int ready = 0;
    int timeout = -1;
    while(1)
    {
        switch(ready = epoll_wait(epfd,evs,len,timeout))
        {
            case 0:
                printf("timeout..\n");
                break;
            case -1:
                printf("epoll_wait");
                break;
            default:
                {
                    int i = 0;
                    for(;i < ready;i++)
                    {
                        int fd = evs[i].data.fd;
                        if(i == 0 && fd == listen_sock && evs[i].events&EPOLLIN)
                        {
                            struct sockaddr_in peer;
                            socklen_t len = sizeof(peer);
                            int new_sock = accept(listen_sock,(struct sockaddr*)&peer,&len);
                            if(new_sock < 0)
                            {
                                perror("accept");
                                return 8;
                            }
                            else
                            {
                                //在epoll_wait之后改变其文件状态,为非阻塞,ET工作
                                set_no_block(new_sock);
                                printf("get new client:ip %s:port %d\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
                                ev.events = EPOLLIN|EPOLLET;
                                ev.data.fd=new_sock;
                                if(epoll_ctl(epfd,EPOLL_CTL_ADD,new_sock,&ev)<0)
                                {
                                    perror("epoll_ctl");
                                    return 9;
                                }
                            }
                        }
                        else
                        {
                            //read
                            if(evs[i].events&EPOLLIN)
                            {
                                char buf[1024];
                                ssize_t _s = my_read(fd,buf);
                                //ssize_t _s = recv(fd,buf,sizeof(buf)-1,0);
                                if(_s > 0)
                                {
                                    buf[_s] = '\0';
                                    printf("client # %s\n",buf);

                                    ev.data.fd = fd;
                                    ev.events = EPOLLOUT |EPOLLET;
                                    epoll_ctl(epfd,EPOLL_CTL_MOD,fd,&ev);
                                }
                                else if(_s == 0)
                                {
                                    //client close
                                    printf("client close...\n");
                                    epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);
                                    close(fd);
                                }
                                else
                                {
                                    perror("my_read");
                                    return 10;
                                }
                            }
                            else if(evs[i].events&EPOLLOUT)
                            {
                                char *msg = "HTTP/1.1 200 ok\r\n\r\n<html><h1>hello Comedly</h1></html>\r\n";
                                //send(fd,msg,sizeof(msg)-1);
                                //send(fd,msg,strlen(msg),0);
                                write(fd,msg,strlen(msg));
                                epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);
                                close(fd);
                            }
                            else
                            {
                                continue;
                            }
                        }
                    }
                }
                break;
        }
    }
    return 0;
}
测试结果:



Linux I/O 多路转接:select 与 epoll 技术剖析 随着互联网应用的规模不断扩大,高并发 I/O 处理成为系统设计的核心挑战之一。本文从 Linux 平台的 I/O 多路转接技术入手,详细解析了 select 与 epoll 两种机制的原理、实现细节与适用场景,同时对未来 I/O 模型的发展方向进行了前瞻性讨论。通过经典代码示例,读者将更直观地理解二者的异同与各自的优劣势。 阅读详情

相关推荐

IDEA 导入 jbolt项目(实验室非公开项目)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录准备一、准备数据库二、IDEA导入jbolt项目 准备 在实验室群文件中下载jbolt.zip和mysql.sql两个文件 将其解压到自己的目录下 一、准备数据库 打开Navicat新建一个jbolt数据库(字符集为utf8) 导入mysql.sql文件 数据库导入完毕 二、IDEA导入jbolt项目 点击打开一个项目 选择jbolt文件夹 以Maven形式打开 打开pom.xml 在里面添加jetty-server依赖

weixin_44094842的博客 974

自己趟过epoll的坑

坑的背景 本人用epoll来实现多路复用,epoll触发模式有两种: ET(边缘模式)LT(水平模式) LT模式 是标准模式,意味着每次epoll_wait()返回后,事件处理后,如果之后还有数据,会不断触发,也就是说,一个套接字上一次完整的数据,epoll_wait()可能会返回多次,直到没有数据为止。 ET模式 也称高效模式,有数据过来后,epoll_wait()会

linuxheik的专栏 1万+

【Docker】搭建一个媒体服务器插件后端API服务 - MetaTube

本教程基于群晖的NAS设备DS423+的docker功能进行搭建,DSM版为 7.2.1-69057 Update 5。MetaTube是一个媒体服务器插件,主要用于Emby和Jellyfin媒体服务器。它的主要功能是从互联网上抓取内容并响应 JSON 数据,然后通过预安装的 MetaTube 插件请求服务器并下载相应的元数据,以与 Jellyfin/Emby 服务器配合使用。使用 MetaTube 的步骤大致如下:部署后端:首先,需要部署一个名为​ 的后端 API 服务器来抓取内容。

小小笔记大大用处 1万+

poll与epoll

poll poll函数接口 #include &lt;poll.h&gt; int poll(struct pollfd *fds,nfds_t nfds,int timeout); //参数1 结构体指针(结构体数组的首地址) //参数2 数组长度 //参数3 poll函数的超时时间(同select) //返回值小于0,出错,等于0,poll函数等待超时 //大于0,表示pol...

王洋的博客 850

Augustus手动安装教程

本文记载了如何结合conda手动安装Augustus

m0_65437087的博客 1257

保姆级教程:用PyTorch从零实现SDE扩散模型(附完整代码与MNIST实战)

本文提供了一份详细的PyTorch教程,指导读者从零开始实现SDE扩散模型,并附有完整的代码示例和MNIST数据集实战。通过解释随机微分方程(SDE)的核心概念、模型架构设计、训练流程实现以及采样生成过程,帮助开发者掌握扩散模型的构建与应用。

weixin_28677005的博客 266

I/O 多路转接epoll

当ET底层缓冲区有数据后,ET只会通知用户进程一次,逼着用户一次要把缓冲区的数据读完,但是用户并不知道缓冲区的数据大小,只能进行循环读取recv,一旦底层缓冲区的数据被读完后,再调用recv如果是阻塞模式就被阻塞了,服务器就会被挂起。struct epoll_event结构中有两个成员,第一个成员events表示的是需要监视的事件,第二个成员data是一个联合体结构,一般选择使用该结构当中的fd,表示需要监听的文件描述符。网络协议栈或驱动层,当某个 fd 上有数据可读、可写或异常时,触发底层的。

jingfeng514的博客 1183

python爬取《你好, 李焕英》豆瓣评论数据

# 导入工具包 import requests from bs4 import BeautifulSoup import time import pandas as pd import numpy as np # 请求头 headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36'} # =

python技巧分享 3457

I/O多路转接——select,poll,epoll

本文介绍了几种不同的多路转接模型,详细谈了一下epoll的工作模式

better_wei的博客 1120

使用MLP解决OCR问题(OpenCV)(下)

分类模型:        分类模型涉及的一个比较关键的问题就是输出的10维向量是如何与具体的类别挂钩的。实际上:10维向量的每一位都代表一类,在对于训练集的表达中,如果输入数据是0,则10维向量的第一位赋值为1,其余均为0。即0对应[1,0,0,0,0,0,0,0,0,0]。MLP模型训练完成后,就需要对用户输入的数据所属类别进行判定。这时得到的输出数据基本不可能是正好的所属类为1,其他位置为0

qq_18515405的专栏 1906

如何绘制电气绝缘图(GB9706.1-2007和GB9706.1-2020差异)

是用来描述要考虑设备的绝缘状况和它们的值 ,从而便于和相关部门交流和沟通,如权威机构和检测实验室等。本文为绝缘图的实例, 包括所有相关的绝缘路径以及介电强度,爬电距离和电气间隙的值。

学海无涯的专栏 1万+

【Linux网络】I/O多路转接技术 - epoll

本篇博文对【Linux网络】I/O多路转接技术 - epoll做了一个较为详细的介绍,不知道对你有没有帮助呢觉得博主写得还不错的三连支持下吧!会继续努力的~

2301_77954967的博客 1589

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

【Linux】I/O 多路转接:select & epoll 技术剖析

本文详细介绍了 Linux 下的 I/O 多路复用技术,包括 select、poll 和 epoll 的原理、优缺点及使用场景。select 和 poll 适用于少量连接,而 epoll 在处理大量并发连接时表现出色,文章通过示例代码展示了如何使用这些技术实现服务器程序,强调了根据实际需求选择合适的 I/O 模型的重要性。

You build it, you run it 3868

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

I/O多路转接之select、poll、epoll详解

select是一个系统调用,用来进行I/O多路转接select可以让程序同时监视多个文件描述符上的事件是否就绪当监视的多个文件描述符中有一个或多个事件就绪时,select才会成功返回并将对应的文件描述符就绪的事件告知调用者。

大学生一枚 1071

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

I/O多路转接 —— epoll

其中文件描述符0、1、2是默认打开的,分别对应的是标准输入、标准输出和标准错误,3号文件描述符对应的是服务器创建的epoll模型,4号文件描述符对应的是监听套接字,5号和6号文件描述符对应的分别是正在访问服务器的两个客户端。在epoll中,对于每一个事件都会有一个对应的epitem结构体,红黑树和就绪队列当中的节点分别是基于epitem结构中的rbn成员和rdllink成员的,epitem结构当中的成员ffd记录的是指定的文件描述符值,event成员记录的就是该文件描述符对应的事件。

m0_73634434的博客 1150

[计算机网络]--I/O多路转接之poll和epoll

poll函数的相关接口,poll函数是如何实现多路转接的,epoll函数的学习,epoll函数的工作原理,poll函数和epoll函数服务器的实现。

分享技术 2278

【探索Linux】P.49(高级IO —— I/O多路转接之epoll )

本文全面介绍了epoll技术,包括其基本概念、相关系统调用(epoll_create、epoll_ctl、epoll_event结构体、epoll_wait)、工作原理(工作流程、事件触发模式)、优势以及使用示例。

Yawesh的博客 1240

I/O多路转接——select、poll、epoll

​ epoll有三个相关的系统调用,分别是epoll_create、epoll_ctl和epoll_wait。

qq_55317476的博客 1726

I/O多路转接之select/poll/epoll

虽然当前的select服务器是一个单进程的服务器,但它却可以同时为多个客户端提供服务,根本原因就是因为select函数调用后会告知select服务器是哪个客户端对应的连接事件就绪了,此时select服务器就可以读取对应客户端发来的数据,读取完后又会调用select函数等待某个客户端连接的读事件就绪。此时如果select监视的文件描述符上有事件就绪,那么select函数的返回值就是大于0的,如果select监视的文件描述符上没有事件就绪,那么select的返回值就是等于0的。

2303_77100822的博客 1321

Linux网络编程——I/O多路转接(2)之 poll、epoll

上篇文章中我们提到了I/O多路转接的select接口select的fd存在着上限每次调用都需要重新设置关心的fd针对select接口中存在的问题,本章中我们再来介绍其他的多路转接的接口——poll接口和epoll接口。

学习日记 1223

详解I/O多路转接模型:select & poll & epoll

文章技术分享思路:从select模型开始,先了解select模型的理论基础,然后编写简单的基于select的tcp服务器,接着分析出select的特点和缺点。引出poll模型,了解了poll模型的基础理论,编写简单的基于poll的tcp服务器。接着引出重要的epoll模型,了解epoll模型的理论以及原理,编写简单的基于epoll的tcp服务器,总结select、poll和epoll的区别,ET模式下epoll高效的原因。

wjmhlh的博客 338

揭秘epoll:高效I/O多路转接核心机制

I/O 多路转接是一种高效处理多个文件描述符(如套接字)的技术,允许单个线程或进程同时监视多个文件描述符的状态变化。epoll 是 Linux 提供的一种 I/O 多路转接机制,相比 select 和 poll,epoll 在大规模并发连接时性能更高,因为它避免了线性扫描所有文件描述符的开销。epoll 采用事件驱动模型,仅关注活跃的文件描述符,避免了 select/poll 的轮询开销。

DyK_8d72的博客 299

I/O多路转接之select、poll、epoll

select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。

SuLiJuan66的专栏 1444

I/O 多路转接之epoll

数据结构分离:红黑树用于快速增删改查监控集,就绪链表用于高效返回就绪事件。事件驱动回调:通过将回调函数注册到文件描述符的等待队列,实现“通知-唤醒”机制,避免无效轮询。灵活的触发模式:水平触发简化编程,边缘触发进一步提升性能,适应不同场景。正是这些设计,使得 epoll 能够轻松应对成千上万的并发连接,成为 Linux 下高性能网络编程的事实标准。

2501_92032664的博客 569

I/O多路转接之【epoll】

epoll 在Linux中,还提供了第三种I/O多路转接的方式,那就是epoll,它几乎具备了select和poll的全部优点,是公认的Linux2.6下的最好的多路I/O就绪通知方法。 先来看一下接口,再根据参数解释epoll的工作原理。epoll将多路转接拆分为三个步骤。 第一步:创建一个epoll语柄 这个函数用来创建一个epoll语柄,其中size一般被忽略,返回值是一个文件描...

ChenYang1998的博客 426
上一篇: I/O多路转接之select
下一篇: 海量数据面试题整理
Comedly
博客等级 码龄10年 17粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值