epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select。epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。并且,在linux/posix_types.h头文件有这样的声明:

#define __FD_SETSIZE 1024 //select最多同时监听1024个fd

当然,可以通过修改头文件再重编译内核来扩大这个数目,但这似乎并不治本。

所以在Nginx中采用了epoll来实现其高并发特性。

工作方式LT(level triggered):水平触发,缺省方式,同时支持block和no-block socket,在这种做法中,内核告诉我们一个文件描述符是否被就绪了,如果就绪了,你就可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错的可能性较小。传统的selectpoll都是这种模型的代表。

ET(edge-triggered):边沿触发,高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪状态时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如:你在发送、接受或者接受请求,或者发送接受的数据少于一定量时导致了一个EWOULDBLOCK错误)。但是请注意,如果一直不对这个fs做IO操作(从而导致它再次变成未就绪状态),内核不会发送更多的通知。

区别:LT事件不会丢弃,而是只要读buffer里面有数据可以让用户读取,则不断的通知你。而ET则只在事件发生之时通知。

主要的数据结构

epoll_event的结构如下:

typedef union epoll_data {void *ptr;intfd; __uint32_t u32; __uint64_t u64;} epoll_data_t;//保存触发事件的某个文件描述符相关的数据structepoll_event { __uint32_t events;/*epoll event*/epoll_data_t data;/*User data variable*/};

events表示感兴趣的事件和被触发的事件,可能的取值为:EPOLLIN对应的文件描述符可以读

EPOLLOUT对应的文件描述符可以写

EPOLLPRI对应的文件描述符有紧急的数可读

EPOLLERR对应的文件描述符发生错误

EPOLLHUP对应的文件描述符被挂断

EPOLLET将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的

EPOLLONESHOT只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

操作函数

epoll的接口非常简单,用三个相关函数来创建epoll句柄、注册epoll事件以及等待事件的发生。

创建epoll句柄:

int epoll_create(intsize);//size表示内核需要监听的数目

//return : epoll文件描述符

需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值(文件标识符),在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

epoll事件注册函数:

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)//epfd是epoll_create()的返回值//op表示动作/*op可被表示为: EPOLL_CTL_ADD:注册新的fd到epfd中; EPOLL_CTL_MOD:修改已经注册的fd的监听事件; EPOLL_CTL_DEL:从epfd中删除一个fd;*///fd是需要监听的fd//event是内核需要监听的事件

等待事件发生函数:

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, inttimeout)//epfd是函数返回值//events是内核监听事件的集合//maxevents是epoll_wait可以处理的连接事件的最大限度值//timeout是超时时间

//返回值:请求数

epoll工作流程

首先,需要调用epoll_create创建epoll,此后我们就可以进行socket/bind/listen,然后调用epoll_ctl进行注册。接下来,就可以通过一个while(1)循环调用epoll_wait来等待事件的发生,然后循环查看接收到的事件并进行处理。如果事件是sever的socketfd我们就要进行accept,并且把接收到client的socketfd加入到要监听的事件中。如果在监听过程中,需要修改操作方式(读/写),可以调用epoll_ctl来重新修改。如果监听到某一个客户端关闭,那么我就需要再次调用epoll_ctl把它从epoll监听事件中删除。

实例

#include #include#include#include#include#include#include#include#include#include#includevoid setnonblocking(intsockfd){intopts; opts=fcntl(sockfd, F_GETFL);if(opts < 0){ perror("fcntl1 error!"); exit(1); } opts= opts |O_NONBLOCK;if(fcntl(sockfd, F_SETFL, opts) < 0){ perror("fcntl2 error!"); exit(1); }}intmain(){intfd;inton;intrs;intlen;intconn;char buffer[100];intflag1, flag2;structsockaddr_in serv_addr, clt_addr;structtimeval timeout;inti;intnfds;intepfd;intnewfd;structepoll_event ev;struct epoll_event events[20]; fd= socket(AF_INET, SOCK_STREAM, 0); on= 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,&on, sizeof(on)); timeout.tv_sec= 5; timeout.tv_usec= 0; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); bzero(&serv_addr, sizeof(structsockaddr_in)); serv_addr.sin_family=AF_INET; serv_addr.sin_port= htons(9090); serv_addr.sin_addr.s_addr=INADDR_ANY; rs= bind(fd, (struct sockaddr*)(&serv_addr), sizeof(structsockaddr));if(rs < 0){ perror(""); close(fd);return -1; } setnonblocking(fd); epfd= epoll_create(100); ev.data.fd=fd; ev.events= EPOLLIN|EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, fd,&ev); rs= listen(fd, 5);if(rs < 0){ perror(""); close(fd);return -1; } len= sizeof(structsockaddr);for(;;){ nfds= epoll_wait(epfd, events, 20, 500);for(i = 0; i < nfds; ++i){if(events[i].data.fd ==fd){ conn= accept(fd, (struct sockaddr*)(&clt_addr), (unsigned int*)(&len)); setnonblocking(conn); ev.data.fd=conn; ev.events= EPOLLIN|EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, conn,&ev); }else if(events[i].events &EPOLLIN){if((newfd = events[i].data.fd) < 0)continue; bzero(buffer,sizeof(buffer)); flag1= recv(newfd, buffer, 100, 0); printf("recv: %s", buffer); printf("recv return: %d", flag1); ev.data.fd=newfd; ev.events= EPOLLOUT|EPOLLET; epoll_ctl(epfd, EPOLL_CTL_MOD, newfd,&ev); }else if(events[i].events &EPOLLOUT){if((newfd = events[i].data.fd) < 0)continue; bzero(buffer,sizeof(buffer)); strcpy(buffer,"ACK"); flag2= send(newfd, buffer, sizeof(buffer), 0); printf("recv return: %d", flag2); ev.data.fd=newfd; ev.events= EPOLLIN|EPOLLET; epoll_ctl(epfd, EPOLL_CTL_MOD, newfd,&ev); } } } close(fd);return 0;}

本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/p/3143953.html,如需转载请自行联系原作者

物联网卡linux,Server Develop (六) Linux epoll总结相关推荐

  1. linux下设置物联网卡apn,负控终端物联网卡APN参数修改步骤

    随着电力负荷管理技术的不断进步,越来越多的负控设备厂商都对负荷控制进行了技术升级,在完成技术升 级后负控设备只能办理及使用移动.联通.电信4G物联卡,在设备安装的过程中需要对负控终端的参数进行 设备修 ...

  2. 什么是物联网卡?物联卡有哪几种类型?

    在我们平常的生活当中,有比较少的人听说过物联网卡,不知道物联网卡是什么东西,而物联网卡这东西在很多年就开始被使用着,只不多在近两年比较火爆而已,而使用物联网卡的原理就是物物相连,通过在某种环境下,将一 ...

  3. 关于物联网卡,你需要知道以下10个常识要点!

    一.物联网卡的基本用途     ?物联卡是三大运营商(移动.联通.电信)基于物联网专网,面向物联网用户提供的移动通信接入业务.采用三网专用(11位或 13位)号段,通过专用网元设备支持无线数据和语音等 ...

  4. 物联网卡11位和13位号码的区别在于哪

    近日,有网友咨询,目前市面上还有没有11位的物联卡号,中景元物联介绍,最早物联卡是11位号码的,是可以语音的一种物联卡,目前已经被13位卡号所取代,而今发现已经很少见到这种物联卡. 物联网卡为什么现在 ...

  5. 移动物联网卡APN如何设置?

    移动物联网卡是智能设备的通信载体,为设备提供网络数据传输服务,主要网络形式有2G/3G/4G/5G,企业设备通过移动物联网卡将数据传输到管理平台,移动物联网卡可支持客户专属APN采用GRE隧道进行数据 ...

  6. 关于物联网卡(二):如何使用物联网卡

    一,首先我们来看一下物联网卡的分类 物联网卡分为插拔式物联网卡和贴片式物联网卡 插拔式物联网卡 外观上就是普通的手机用SIM卡的样子,根据材质可以分为工业级物联网卡,和普通物联网卡 1.工业级物联网卡 ...

  7. android梦网物联卡信息,梦网物联云:实现智能穿戴只需一张物联网卡

    近年来智能穿戴行业发展迅速,智能手环.智能手表.智能眼镜等智能穿戴设备日渐普及,不仅年轻人被智能穿戴设备吸引,老年人和小孩也慢慢用上了智能穿戴设备,智能穿戴设备正在悄无声息地对我们的生活产生影响. 据 ...

  8. 分析|什么是物联网卡

    物联网产品日渐走进我们的工作生活中,而物联网卡作为连接智能硬件和物联网络的桥梁,在整个物联网中起着至关重要的作用.那么如此重要的物联网卡长啥样呢?今天我们就一起来了解下物联网卡的产品形态以及三大运营商 ...

  9. 带你正确认识物联网卡

    在互联网时代下,各种智能设备都离不开数据流量,无论是我们个人手机上网.笔记本上网.电脑上网,还是企业硬件设备联网都需要用到数据流量,为了将两者区分开来,三大运营商相继推出了物联网流量卡专门提供给企业硬 ...

  10. 51物联卡:你身边有哪些智能设备用上了物联网卡?

    近些年,物联卡也越来越受关注,许多企业在设备连网方面,也都从传统流量卡而换成了物联网卡,比如大家都熟悉的我们生活中常用的POS机,智能机器人,共享单车等等,除此之外,你还知道有哪些设备用上了物联网卡吗 ...

最新文章

  1. HDU 1513 Palindrome(最长公共子序列)
  2. webview重新加载(reload)或者发起 redirect request导致js和objc代码之间的bridge失联解决方案(亲测有效)...
  3. Netty 支持的功能与特性
  4. element手机验证格式_vue封装 element-ui form表单验证 正则匹配手机号 自定义校验表格内容...
  5. java查询未提交事务的数据_Jfinal同一事务中已插入的数据记录在事务未提前前查询不到?...
  6. 李洪强iOS之集成极光推送二iOS 证书 设置指南
  7. T电脑经典基础知识技术OC
  8. 怎樣制作线段动画_PPT如何制作简易动画
  9. 异步社区免费电子书下载爬虫实验攻略
  10. 基于Matlab矩形孔径的菲涅耳衍射
  11. base64原理解析
  12. 华为HG8120C光猫换天邑TEWA-600AGM(百兆换千兆)的过程记录
  13. WLC开机卡在launching....(变砖)
  14. MaaS无缝出行服务呼之欲出 传统出行模式将被颠覆
  15. 关于联想Y700,玩游戏闪屏
  16. oracle语句查询时间范围
  17. hongyi lee hw02-03
  18. cad高程测绘图lisp_已知CAD中的高程测绘图,很多点,如何求出所有高程的平均值呢?难道只能用计算器一个一个的相加来算吗?...
  19. 【FPGA实例】基于FPGA的DDS信号发生器设计
  20. 用虚数做计算机代码,小E教你们如何用计算机算虚数

热门文章

  1. Qt调用动态链接库ControlCAN.dll实例
  2. C/C++报错:全局变量重定义或是多次定义
  3. androidstudio环境配置常见问题解决
  4. linux io负载解决方法,看你的linux负载 io值
  5. Upload-labs闯关
  6. SQL注入——基于联合查询的字符型GET注入(三)
  7. windows主机加固和评测
  8. 计算机设备记录人耳感知不到的声音,现代教育技术考试复习资料新
  9. vue中mixins的理解
  10. 关于微信小程序使用wx.downloadFile和wx.getFileSystemManager().saveFile()保存文件在本机找不到文件的说明