目录

1. epoll和select的区别

2. epool提供的函数

2.1 epoll_create

2.2 epoll_ctl

2.3 epoll_wait

3. LT模式和ET模式

4. 程序代码

总结


1. epoll和select的区别

I/O多路有select和epoll。

select当有事件发生时,会去轮训检查加入的1-max的全部监控集合的描述符,找到发生事件的fd。显而易见,当待监控连接是数以十万计的,返回的只是数百个活跃连接事件,这就是低效率的表现。可见,处理并发上万个连接时,select就完全力不从心了。

epoll同样可以实现select做的事情,而且更高效。

  1. 返回 ==  epoll_fd描述符
  2. poll_create() epoll_ctrl(epoll_fd描述符,添加或者删除待监控的连接fd)
  3. 返回事件的活跃连接fd == epoll_wait( epoll描述符 )

与select相比,epoll只会返回发生事件的events集合和发生事件的数量,效率高。

2. epool提供的函数

2.1 epoll_create

#include <sys/epoll.h>int epoll_create(int size)函数说明:参数size:必须设置一个大于0的值。返回值:调用成功返回一个非负值的文件描述符fd,调用失败返回-1。

2.2 epoll_ctl

有了epoll_fd之后,我们需要将我们需要检测事件的其他fd绑定到这个epoll_fd上,或者修改一个已经绑定上去的fd的事件类型,或者在不需要时将fd从epollfd上解绑,需要使用epoll_ctl函数。

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

函数说明:

  1. 参数epfd:调用epoll_create函数创建的epoll_fd。
  2. 参数op:操作类型,取值有EPOLL_CTL_ADD、EPOLL_CTL_MOD和EPOLL_CTL_DEL,分别表示向epoll_fd上添加、修改和移除一个其他fd,当取值是EPOLL_CTL_DEL,第四个参数event忽略不计,可以设置为NULL。
  3. 参数fd:即需要被操作的fd。
  4. 参数event:是一个epoll_event结构体的地址,epoll_event结构体定义下面会详细介绍。
  5. 返回值:调用成功返回0,调用失败返回-1,可以通过errno错误码获取具体的错误原因。

epoll_event结构体定义如下:

struct epoll_event {uint32_t  events; // 需要检测的fd事件,取值与poll函数一样epoll_data_t data; // 用户自定义数据};typedef union epoll_data {void    *ptr;int      fd;   //监控的fduint32_t u32;uint64_t u64;} epoll_data_t;

epoll_event支持的事件宏如下表:

事件宏

描述

EPOLLIN

数据可读(包括普通数据&优先数据)

EPOLLOUT

数据可写(包括普通数据&优先数据)

EPOLLRDHUP

TCP连接被对端关闭,或者关闭了写操作

EPOLLPRI

高优先级数据可读,例如TCP带外数据

EPOLLERR

错误

EPOLLHUP

挂起

EPOLLET

边缘触发模式

EPOLLONESHOT

最多触发其上注册的事件一次

2.3 epoll_wait

创建了epoll_fd,设置好某个fd上需要检测事件并将该fd绑定到epoll_fd上去后,就调用epoll_wait检测事件了。

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

函数说明:

  1. 参数epfd:调用epoll_create函数创建的epoll_fd。
  2. 参数events:是一个epoll_event结构数组的首地址,这是一个输出参数,函数调用成功后,events中存放的是与就绪事件相关epoll_event结构体数组。
  3. 参数maxevents:数组元素的个数。
  4. 参数timeout:超时时间,单位是毫秒,如果设置为0,epoll_wait会立即返回。-1 阻塞等待,有事件循环。>0 定时,毫秒。
  5. 返回值:调用成功会返回有事件的fd数目;如果返回0表示超时;调用失败返回-1。

3. LT模式和ET模式

设置方式

ev.events = EPOLLIN;//使用默认LT模式

ev.events = EPOLLIN|EPOLLET;//监听读状态同时设置ET模式

LT:(Level_triggered,水平触发):

当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你,如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率。

        当接收buffer长度小于接收缓存区数据的长度时,会分包,会连续出发事件多次,循环recv,直到接收完。

ET:(Edge_triggered,边缘触发):

当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你,这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符。

4. 程序代码

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <string.h>#define BUFFER_LENGTH  8196
#define EVENTS_LENGTH   128char rbuffuf[BUFFER_LENGTH] = {0};
char wbuffuf[BUFFER_LENGTH] = {0};int main() {// blockint listenfd = socket(AF_INET, SOCK_STREAM, 0);  // if (listenfd == -1) return -1;
// listenfdstruct sockaddr_in servaddr;servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(9999);if (-1 == bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) {return -2;}//fd --> epollint epfd = epoll_create(1); //只需大于零struct epoll_event ev, events[EVENTS_LENGTH];ev.events = EPOLLIN;ev.data.fd = listenfd;epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev); //epoll非阻塞printf("fd : %d , %d \n", epfd, listenfd);while(1){int nready = epoll_wait(epfd, events, EVENTS_LENGTH, 1000);printf("----- nready = %d\n", nready);int i = 0;for(i = 0; i<nready; i++){int clientfd =  events[i].data.fd; //发生事件的fd.if(listenfd == clientfd){ //severstruct sockaddr_in client;socklen_t len = sizeof(client);int counfd = accept(listenfd, (struct sockaddr*)&client, &len);if(counfd == -1)break;printf("accept = %d  \n" , counfd);ev.events = EPOLLIN ;ev.data.fd = counfd;epoll_ctl(epfd, EPOLL_CTL_ADD, counfd, &ev); //epoll非阻塞}else if(events[i].events & EPOLLIN){ //client 读int n = recv(clientfd, rbuffuf, BUFFER_LENGTH, 0);if(n > 0){rbuffuf[n] = '\0';printf("recv = %s, n =%d\n", rbuffuf, n);memcpy(wbuffuf, rbuffuf , BUFFER_LENGTH);ev.events = EPOLLOUT ;ev.data.fd = clientfd;epoll_ctl(epfd, EPOLL_CTL_MOD, clientfd , &ev);}}else if(events[i].events & EPOLLOUT){ //写int sendlen = send(clientfd, wbuffuf, BUFFER_LENGTH, 0);printf("sendlen =%d\n", sendlen);ev.events = EPOLLIN ;ev.data.fd = clientfd;epoll_ctl(epfd, EPOLL_CTL_MOD, clientfd , &ev);}        }}
}

总结

  1. epoll监视的描述符数量不受限制
  2. epoll不同于select和poll轮询的方式,而是通过每个fd定义的回调函数来实现的,只有就绪的fd才会执行回调函数。

一般在fd数量比较多,但某段时间内,就绪事件fd数量较少的情况下,epoll才会体现出它的优势,也就是说socket连接数量较大时而活跃连接较少时epoll模型更高效。

socket -- epoll模型相关推荐

  1. socket epoll模型

    linux 使用epoll主要目的是啥 为了实现非阻塞么? socket本来就有阻塞和非阻塞两种模式,与epoll无关. epoll是针对多socket操作(从select升级到poll再到epoll ...

  2. Linux网络服务器epoll模型的socket通讯的实现(一)

    准备写一个网络游戏的服务器的通讯模块,参考网上看到的一些代码,在linux下面实现一个多线程的epoll模型的socket通讯的代码,以下是第一部分多线程的切换代码: 1 #include <s ...

  3. linux socket编程epoll模型实现群发消息

    1.实现功能 本代码主要实现了socket编程epoll模型实现多个客户端连接服务器,客户端可以进行群发消息和接收用户输入文本信息,然后发送该信息给服务器,服务器收到后发送应答信息.客户端接收并显示该 ...

  4. socket 通信之 epoll模型

    //socket 通信之 epoll 模型 #include <sys/epoll.h>struct epoll_event{uint32_t events;//需要检测的fd事件,取值与 ...

  5. 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较

    在<朴素.Select.Poll和Epoll网络编程模型实现和分析--模型比较>一文中,我们分析了各种模型在处理短连接时的能力.本文我们将讨论处理长连接时各个模型的性能.(转载请指明出于b ...

  6. 朴素、Select、Poll和Epoll网络编程模型实现和分析——Epoll模型

    在阅读完<朴素.Select.Poll和Epoll网络编程模型实现和分析--Select模型>和<朴素.Select.Poll和Epoll网络编程模型实现和分析--Poll模型> ...

  7. linux epoll模型

    原文:http://yjtjh.blog.51cto.com/1060831/294119 Linux I/O多路复用技术在比较多的TCP网络服务器中有使用,即比较多的用到select函数.Linux ...

  8. Socket拉屎模型之二--实践篇

    前言:本篇没有介绍最好的IO模型 epoll(非阻塞异步),是性能最好的.但是本篇不做介绍. http://www.ibm.com/developerworks/cn/linux/l-async/ h ...

  9. 0729------Linux网络编程----------使用 select 、poll 和 epoll 模型 编写客户端程序

    1.select 模型 1.1 select 函数原型如下,其中 nfds 表示的描述符的最大值加1(因为这里是左闭右开区间),中间三个参数分别表示要监听的不同类型描述符的集合,timeout用来表示 ...

  10. 【转】Epoll模型

    Linux 2.6内核中提高网络I/O性能的新方法-epoll I/O多路复用技术在比较多的TCP网络服务器中有使用,即比较多的用到select函数. 1.为什么select落后     首先,在Li ...

最新文章

  1. MySQL优化篇:数据准备
  2. Math Adventures with Python
  3. Java的工厂模式(三)
  4. 【学术相关】考研生对导师“嚣张发言”引热议:希望您今年招个女同学,不然我换导师!...
  5. Redis数据持久化之AOF持久化
  6. java---Socket编程出现的异常种类
  7. 初一模拟赛总结(3.16)
  8. win10 hyper-v 虚拟机ping不通宿主机问题
  9. 关于ggplot2的一些用法
  10. android命令行 gles,Android利用OpenGLES绘制天空盒实例教程
  11. 快排 递归与非递归实现 优化
  12. zabbix监控oracle rac,CentOS6.9下zabbix3.4.9通过orabbix1.2.3来监控oracle11gRAC
  13. TDA4VM芯片手册阅读笔记
  14. iexplore应用程序错误
  15. PPT超实用的23个快捷键
  16. 存储过程与函数-创建存储过程
  17. 麦克斯韦方程组学习心得与记录
  18. 惠普136w耗材贵吗_惠普136w更换硒鼓之后磨粉极低 惠普136w原装硒鼓能加碳粉吗...
  19. Getting help from shells
  20. VMware的下载安装

热门文章

  1. 调用接口获得地区,再根据地区判断对应编号
  2. 【一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成】
  3. 使用LoadRunner进行并发测试、压力测试和负载测试
  4. 网上书城项目-LoadRunner压力测试
  5. 摩尔斯电码对照表—Morse code
  6. CentOS7下EasyDarwin的安装搭建
  7. python下载互联网上的的图片
  8. 机器学习中的数学——激活函数(一):Sigmoid函数
  9. Bootstrap导航条
  10. 软件功能测试点---总结大全