1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Linux网络编程(六)-高并发服务器03-I/O多路复用03:epoll【红黑树;根节点为监听节

Linux网络编程(六)-高并发服务器03-I/O多路复用03:epoll【红黑树;根节点为监听节

时间:2019-04-07 06:29:06

相关推荐

Linux网络编程(六)-高并发服务器03-I/O多路复用03:epoll【红黑树;根节点为监听节

一、epoll概述

epoll的本质是一个【红黑树】。监听结点为根节点。

大量并发,少量活跃效率高。

epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。

目前epelllinux大规模并发网络程序中的热门首选模型。

1、epoll特点

没有文件描述符1024的限制;将需要监听的文件描述符上树之后,以后每次监听都不要再次将需要监听的文件描述符拷贝到内核;返回的是已经变化的文件描述符,不需要遍历红黑树;

2、epoll工作原理

红黑树:树上每个节点都是一个epoll_event结构体

epoll除了提供select/poll那种IO事件的电平触发(Level Triggered)外,还提供了边沿触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

可以使用cat命令查看一个进程可以打开的socket描述符上限。

cat /proc/sys/fs/file-max

如有需要,可以通过修改配置文件的方式修改该上限值。

sudo vi /etc/security/limits.conf在文件尾部写入以下配置,soft软限制,hard硬限制。如下图所示。* soft nofile 65536* hard nofile 100000

二、epoll的基础API(3个)

1、创建红黑树【epoll_create()】

创建一个epoll句柄,参数size用来告诉内核监听的文件描述符的个数,跟内存大小有关。

#include <sys/epoll.h>int epoll_create(int size)

参数:

size:监听的文件描述符的上限数量(内核参考值),2.6版本之后填1即可;Since Linux 2.6.8, the size argument is ignored, but must be greater than zero;返回值(树的句柄): 成功:非负文件描述符;returns a file descriptor referring to the new epoll instance. This file descriptor is used for all the subsequent calls to theepoll interface. When no longer required, the file descriptor returned by epoll_create() should be closed by using close(2). When all file descriptors referring to an epoll instance have been closed, the kernel destroys the instance and releases the associated resources for reuse.失败:-1,设置相应的errno

2、将需要监听的“文件描述符”上树、下树、修改【epoll_ctl()】

控制某个epoll监控的文件描述符上的事件:注册、修改、删除。

#include <sys/epoll.h>int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

参数:

epfd:为epoll_creat创建的红黑树树的句柄op:表示动作,用3个宏来表示: EPOLL_CTL_ADD (注册新的fdepfd):上树;EPOLL_CTL_MOD (修改已经注册的fd的监听事件):修改;EPOLL_CTL_DEL (从epfd删除一个fd):下树fd:待处理(上树、下树、修改)的“文件描述符”;上树之后对应event;event:上树的节点(告诉内核需要监听的事件);

typedef union epoll_data {void *ptr;intfd;uint32_tu32;uint64_tu64;} epoll_data_t;struct epoll_event {uint32_tevents;需要监听的时间 /* Epoll events */epoll_data_t data; 需要监听的文件描述符 /* User data variable */};

结构体epoll_event中的events选项:

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

2.1 将文件描述符上树

创建红黑树

int myepfd = epoll_create(1);

将文件描述符cfd上树

struct epoll_event ev;ev.data.fd = cfd;ev.events = EPOLLIN; // 待监听的事件为“read”事件// 上树// 待操作的树为myepfd// 上树的文件描述符为cfd,对应的树上的节点为 &evepoll_ctl(myepfd, EPOLL_CTL_ADD, cfd, &ev);

3、监听【epoll_wait()】

#include <sys/epoll.h>int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

参数:

epfd:树的句柄;events:用来存内核得到事件的集合,可简单看作数组(接收树上变化的节点的数组的首地址)。maxevents: 数组events的大小,这个maxevents的值不能大于创建epoll_create()时的size,timeout: 是超时时间 -1: 阻塞(永久监听) 0: 立即返回,非阻塞 >0: 指定毫秒返回值: 成功返回变化的文件描述符的数量,出错返回-1

三、epoll案例

1、epoll监听无名管道pipe

#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/epoll.h>int main(int argc, char *argv[]){//创建数组,用于保存管道的2个文件描述符(一个读端,一个写端)int fd[2]; //创建无名管道pipe(fd);//创建子进程pid_t pid;pid = fork();if(pid < 0)perror("");else if(pid == 0)// 子进程{close(fd[0]); // 关闭pipe的读端,只给父进程写数据发过去char buf[5];char ch='a';while(1){sleep(3);memset(buf,ch++,sizeof(buf)); // 第一次写a,第二次写b...write(fd[1], buf, 5);}}else// 父进程{close(fd[1]); // 关闭pipe的写端,只读取从子进程过来的数据//创建树int epfd = epoll_create(1);struct epoll_event ev,evs[1];ev.data.fd = fd[0];ev.events = EPOLLIN;//上树epoll_ctl(epfd,EPOLL_CTL_ADD,fd[0],&ev);//监听while(1){int n = epoll_wait(epfd,evs,1,-1);if(n == 1){char buf[128]="";int ret = read(fd[0],buf,sizeof(buf));if(ret <= 0){close(fd[0]);epoll_ctl(epfd,EPOLL_CTL_DEL,fd[0],&ev);break;}else{printf("%s\n",buf);}}}}return 0;}

Linux网络编程多路IO复用----epoll_城南花已开.jpg的博客-CSDN博客

Linux网络编程(六)-高并发服务器03-I/O多路复用03:epoll【红黑树;根节点为监听节点】【无宏FD_SETSIZE限制;不需每次都将要监听的文件描述符从应用层拷贝到内核;不需遍历树】

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。