epoll的两种工作模式

摘要:
Epoll有两种模式,边缘触发(简称ET)和水平触发(简称LT)。使用这两种模式时,应注意,如果使用ET模式,则仅当状态发生变化时才会发出通知。LT模式与最初的选择/轮询操作类似,只有在存在尚未处理的事件时,通知才会继续。使用代码解释问题:首先,给出服务器代码。需要说明的是,每次进行接受连接时,都会使用ET模式添加可读性集
epoll有两种模式,Edge Triggered(简称ET) 和 Level Triggered(简称LT).在採用这两种模式时要注意的是,假设採用ET模式,那么仅当状态发生变化时才会通知,而採用LT模式类似于原来的select/poll操作,仅仅要还有没有处理的事件就会一直通知. 

以代码来说明问题: 
首先给出server的代码,须要说明的是每次accept的连接,增加可读集的时候採用的都是ET模式,并且接收缓冲区是5字节的,也就是每次仅仅接收5字节的数据: 
Java代码  收藏代码
  1. #include <iostream>  
  2. #include <sys/socket.h>  
  3. #include <sys/epoll.h>  
  4. #include <netinet/in.h>  
  5. #include <arpa/inet.h>  
  6. #include <fcntl.h>  
  7. #include <unistd.h>  
  8. #include <stdio.h>  
  9. #include <errno.h>  
  10.   
  11. using namespace std;  
  12.   
  13. #define MAXLINE 5  
  14. #define OPEN_MAX 100  
  15. #define LISTENQ 20  
  16. #define SERV_PORT 5000  
  17. #define INFTIM 1000  
  18.   
  19. void setnonblocking(int sock)  
  20. {  
  21.     int opts;  
  22.     opts=fcntl(sock,F_GETFL);  
  23.     if(opts<0)  
  24.     {  
  25.         perror("fcntl(sock,GETFL)");  
  26.         exit(1);  
  27.     }  
  28.     opts = opts|O_NONBLOCK;  
  29.     if(fcntl(sock,F_SETFL,opts)<0)  
  30.     {  
  31.         perror("fcntl(sock,SETFL,opts)");  
  32.         exit(1);  
  33.     }     
  34. }  
  35.   
  36. int main()  
  37. {  
  38.     int i, maxi, listenfd, connfd, sockfd,epfd,nfds;  
  39.     ssize_t n;  
  40.     char line[MAXLINE];  
  41.     socklen_t clilen;  
  42.     //声明epoll_event结构体的变量,ev用于注冊事件,数组用于回传要处理的事件  
  43.     struct epoll_event ev,events[20];  
  44.     //生成用于处理accept的epoll专用的文件描写叙述符  
  45.     epfd=epoll_create(256);  
  46.     struct sockaddr_in clientaddr;  
  47.     struct sockaddr_in serveraddr;  
  48.     listenfd = socket(AF_INET, SOCK_STREAM, 0);  
  49.     //把socket设置为非堵塞方式  
  50.     //setnonblocking(listenfd);  
  51.     //设置与要处理的事件相关的文件描写叙述符  
  52.     ev.data.fd=listenfd;  
  53.     //设置要处理的事件类型  
  54.     ev.events=EPOLLIN|EPOLLET;  
  55.     //ev.events=EPOLLIN;  
  56.     //注冊epoll事件  
  57.     epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);  
  58.     bzero(&serveraddr, sizeof(serveraddr));  
  59.     serveraddr.sin_family = AF_INET;  
  60.     char *local_addr="127.0.0.1";  
  61.     inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);  
  62.     serveraddr.sin_port=htons(SERV_PORT);  
  63.     bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));  
  64.     listen(listenfd, LISTENQ);  
  65.     maxi = 0;  
  66.     for ( ; ; ) {  
  67.         //等待epoll事件的发生  
  68.         nfds=epoll_wait(epfd,events,20,500);  
  69.         //处理所发生的全部事件       
  70.         for(i=0;i<nfds;++i)  
  71.         {  
  72.             if(events[i].data.fd==listenfd)  
  73.             {  
  74.                 connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);  
  75.                 if(connfd<0){  
  76.                     perror("connfd<0");  
  77.                     exit(1);  
  78.                 }  
  79.                 //setnonblocking(connfd);  
  80.                 char *str = inet_ntoa(clientaddr.sin_addr);  
  81.                 cout << "accapt a connection from " << str << endl;  
  82.                 //设置用于读操作的文件描写叙述符  
  83.                 ev.data.fd=connfd;  
  84.                 //设置用于注測的读操作事件  
  85.                 ev.events=EPOLLIN|EPOLLET;  
  86.                 //ev.events=EPOLLIN;  
  87.                 //注冊ev  
  88.                 epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);  
  89.             }  
  90.             else if(events[i].events&EPOLLIN)  
  91.             {  
  92.                 cout << "EPOLLIN" << endl;  
  93.                 if ( (sockfd = events[i].data.fd) < 0)   
  94.                     continue;  
  95.                 if ( (n = read(sockfd, line, MAXLINE)) < 0) {  
  96.                     if (errno == ECONNRESET) {  
  97.                         close(sockfd);  
  98.                         events[i].data.fd = -1;  
  99.                     } else  
  100.                         std::cout<<"readline error"<<std::endl;  
  101.                 } else if (n == 0) {  
  102.                     close(sockfd);  
  103.                     events[i].data.fd = -1;  
  104.                 }  
  105.                 line[n] = '

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【转】锋狂百科:手机也能接外设 OTG技术详解Linux下查看占用CPU与内存最高的进程下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Redis服务设计(处理流程、事件模型、多路复用)

简介 Redis作者: 意大利人 Salvatore Sanfilippo(网名 Antirez) 开发。Antirez 不仅帅的不像实力派,也非常有趣。Antirez 今年已经四十岁了,依旧在孜孜不倦地写代码,为 Redis 的开源事业持续贡献力量。 Redis是一个开放源代码(BSD许可)内存中的数据结构存储,用作数据库、缓存和消息代理。它支持字符串、...

单进程单线程的Redis如何能够高并发

1、基本原理 采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗) (1)为什么不采用多进程或多线程处理? 多线程处理可能涉及到锁 多线程处理会涉及到线程切换而消耗CPU (2)单线程处理的缺点? 无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善 2、Redis不存在线程安全问题? Redis采...

epoll惊群原因分析

考虑如下情况(实际一般不会做,这里只是举个例子): 在主线程中创建一个socket、绑定到本地端口并监听 在主线程中创建一个epoll实例(epoll_create(2)) 将监听socket添加到epoll中(epoll_ctl(2)) 创建多个子线程,每个子线程都共享步骤2里创建的同一个epoll文件描述符,然后调用epoll_wait(2)等待事...

2020找工作遇到的一些面试题-C++服务器方向

游卡桌游: epoll网络模型了解多少 服务器调优举例 C++11 lambba表达式 boost库用过没 C与Lua之间的通信 未来的规划 有没有阅读过开源代码,有什么想法 边锋游戏 单例设计模式  (双重锁定) share_ptr 指针泄漏怎么解        (weakptr) std::move 是什么意思   两个线程用同一个种子,获取的...

socket网络编程(四)——epoll多路复用问题

1、epoll诞生的原因 问大家一个问题,如果要设计一款有着千万级别并发的系统,你的客户端和服务端的网络通信底层该怎么设计?我在上一篇文章(socket网络编程(三)——select多路复用问题)中有说到用select可以实现IO多路复用,但是select的设计有瓶颈所在,超过十万的并发效率就非常慢。那么着又该怎么办呢? 于是epoll就腾空出世了! 2、...

Linux高级I/O机制

Linux高级I/O机制 Linux高级I/O机制 2011-08-20 14:11 一、课程目标 I/O常常是现代应用程序的性能瓶颈,为突破这个瓶颈,现代操作系统不断推出新的I/O机制,使高性能的I/O编程变成可能。本次课程将讨论Linux下几种高性能I/O的机制,这些功能都是基于成熟的系统调用,通过本次课程的学习,学员将掌握以下内容:...