Linux中有很多I/O多路复用的机制,其中epoll是比较常用的一种。epoll可以用来监听一个文件描述符,当其中任意一个文件描述符有数据可读或可写时,会通过回调函数通知应用程序进行相应的处理。在高并发的网络编程中,使用epoll可以大幅度提高程序的并发性和响应速度。本文将介绍使用epoll进行网络编程的相关知识和使用方法。
创新互联专注于浚县企业网站建设,成都响应式网站建设,购物商城网站建设。浚县网站建设公司,为浚县等地区提供建站服务。全流程按需网站开发,专业设计,全程项目跟踪,创新互联专业和态度为您提供的服务
一、epoll的工作原理
epoll的工作原理相对于其他I/O多路复用机制而言比较复杂。当我们调用epoll_create函数时,会返回一个文件描述符epfd。我们可以通过epoll_ctl函数来向epfd中添加或删除文件描述符,或者对其进行一些控制操作。当我们需要对epfd的所有文件描述符进行监听时,可以调用epoll_wt函数,该函数会一直阻塞直到有文件描述符有数据可读或可写。
二、epoll的优点
epoll的优点主要体现在以下几个方面:
1. 支持大量的并发连接,可以监听上万个文件描述符。
2. 支持高效的事件通知机制,当有文件描述符有数据可读或可写时,会立即通知应用程序。
3. 支持边缘触发和水平触发两种模式,可以根据实际需求进行选择。
4. 支持使用epoll_ctl函数对监听的文件描述符进行添加、删除和修改操作,非常灵活。
三、epoll的使用方法
1. 创建epoll对象
我们可以通过epoll_create函数来创建epoll对象,该函数会返回一个文件描述符epfd,该描述符用来操作epoll对象。
“`
#include
int epoll_create(int size);
“`
参数size指定epoll对象中能够监听的文件描述符数量,该参数在Linux 2.6.8以后已经不再使用。如果该参数被设置为0,则epoll_create函数会自动根据系统的默认值创建epoll对象。
2. 向epoll对象中添加文件描述符
我们可以通过epoll_ctl函数向epoll对象中添加或删除文件描述符,或者修改其监听事件的属性。
“`
#include
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
“`
参数epfd指定了需要操作的epoll对象的文件描述符,参数op指定了操作类型,参数fd表示需要监听的文件描述符,参数event则描述了需要监听的事件类型。
下面是event结构体的定义:
“`
struct epoll_event {
uint32_t events; /* 监听的事件类型,可以是EPOLLIN、EPOLLOUT、EPOLLRDHUP等 */
epoll_data_t data; /* 回调函数参数 */
};
“`
我们可以通过events参数指定需要监听的事件类型,比如数据可读、数据可写、关闭连接等。在使用epoll的过程中,常常要用到以下几种事件类型:
“`
EPOLLIN:表示文件可读。
EPOLLOUT:表示文件可写。
EPOLLERR:表示文件出现错误。
EPOLLRDHUP:表示文件的连接被断开。
EPOLLHUP:表示连接被挂起。
“`
3. 进行epoll_wt监听
我们可以通过epoll_wt函数监听epoll对象中的文件描述符,当有文件描述符有数据可读或可写时,会立即通知应用程序。
“`
#include
int epoll_wt(int epfd, struct epoll_event *events, int maxevents, int timeout);
“`
参数epfd指定了需要监听的epoll对象的文件描述符,参数events用来存储已经发生事件的文件描述符和事件类型,参数maxevents表示更大需要监听的事件数量,参数timeout表示epoll_wt函数的超时时间。
epoll_wt函数会阻塞直到有文件描述符有数据可读或可写。当epoll_wt函数返回时,events参数中存储的就是已经发生的事件。
4. 处理epoll_wt返回的事件
在使用epoll进行网络编程时,常常需要在epoll_wt返回后对事件进行处理。通常的做法是遍历事件列表,针对每个事件单独进行处理。
下面是一个示例代码:
“`
struct epoll_event events[1024];
int nfds = epoll_wt(epfd, events, 1024, -1);
for (int i = 0; i
int sockfd = events[i].data.fd;
if (events[i].events & EPOLLIN) { // 可读事件
// 处理数据读取逻辑
} else if (events[i].events & EPOLLOUT) { // 可写事件
// 处理数据发送逻辑
} else {
// 处理其他事件,比如连接关闭、连接错误等
}
}
“`
在实际使用中,我们还需要关闭文件描述符、重新注册事件等一些操作。但以上代码已经涵盖了epoll的基本使用方法。
四、
相关问题拓展阅读:
在
select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一
个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制伍历宽烂桐,迅速激活这腔亮个文件描述符,当进程调用epoll_wait()
时便得到通知。
管道
管道的概念:
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间腊仔掘,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:
① 数据自己读不能自己写。
② 数据一旦被读走,便不在管道中存在,不可反复读取。
③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
④ 只能在有公共祖先的进程间使用管道。
常见的通信方式有,单工通信、半双工通信、全双工通信。
简单来说这个管道是一个文件,但又和普通轮核文件不通:管道缓冲区大小一般为1页,即4K字节,管道分读端和写端,读端负责从管道拿数据,当数据为空时则阻塞;写端向管道写数据,当管道缓存区满时则阻塞。
pipe函数
创建管道
int pipe(int pipefd); 成功:0;失败:-1,设置errno
函数调用成功返回r/w两个文件描述符。无需open,但需手动close。规定:fd → r; fd → w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。
管道创建成功以后,创建该管道的进程(父进程)同时掌握着管道的读端和写端。如何实现父子进程间通信呢?通常可以采用如下步骤:
1. 父进程调用pipe函数创建管道,得到两个文件描述符fd、fd指向管道的读端和写端。
2. 父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。
3. 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道戚芹是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。
管道的读写行为
使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):
1. 如果所有指向管道写端的文件描述符都关闭了(管道写端引用计数为0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。
2. 如果有指向管道写端的文件描述符没关闭(管道写端引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
3. 如果所有指向管道读端的文件描述符都关闭了(管道读端引用计数为0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。当然也可以对SIGPIPE信号实施捕捉,不终止进程。具体方法信号章节详细介绍。
4. 如果有指向管道读端的文件描述符没关闭(管道读端引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。
总结:
① 读管道: 1. 管道中有数据,read返回实际读到的字节数。
2. 管道中无数据:
(1) 管道写端被全部关闭,read返回0 (好像读到文件结尾)
(2) 写端没有全部被关闭,read阻塞等待(不久的将来可能有数据递达,此时会让出cpu)
② 写管道: 1. 管道读端全部被关闭, 进程异常终止(也可使用捕捉SIGPIPE信号,使进程不终止)
2. 管道读端没有全部关闭:
(1) 管道已满,write阻塞。
(2) 管道未满,write将数据写入,并返回实际写入的字节数。
Epoll的概念
Epoll可以使用一次等待监听多个描述符的可读/可写状态.等待返回时携带了可读的描述符或者自定义的数据.不需要为每个描述符创建独立的线程进行阻塞读取,
Linux系统中的epoll机制为处理大批量句柄而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著减少程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率
(01) pipe(wakeFds),该函数创建了两个管道句柄。
(02) mWakeReadPipeFd=wakeFds,是读管道的句柄。
(03) mWakeWritePipeFd=wakeFds 1 ,是写管道的句柄。
(04) epoll_create(EPOLL_SIZE_HINT)是创建epoll句柄。
(05) epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem),它的作用是告诉mEpollFd,它要监控mWakeReadPipeFd文件描述符的EPOLLIN事件,即当管道中有内容可读时,就唤醒当前正在等待管道中的内容的线程。
回到Android中的epoll大致流程如下:
Looper.loop -> MessageQueue.nativePollOnce
epoll_create() epoll_ctl() 注册事件的回调
looper.pollInner() -> epoll_wait() 等待接受事件唤醒的回调
MessageQueue.enqueueMessage(Message msg, long when) -> MessageQueue.nativeWake(long ptr)
参考链接如下
链接:
链接:
linux epoll库的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux epoll库,深入浅出:Linux中epoll库之使用方法,Linux中select poll和epoll的区别,浅谈Android之Linux pipe/epoll的信息别忘了在本站进行查找喔。
成都创新互联建站主营:成都网站建设、网站维护、网站改版的网站建设公司,提供成都网站制作、成都网站建设、成都网站推广、成都网站优化seo、响应式移动网站开发制作等网站服务。
网站题目:深入浅出:Linux中epoll库之使用方法(linuxepoll库)
当前地址:http://www.shufengxianlan.com/qtweb/news26/102826.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联