网络上有所素材都说epoll是高并发、单线程、IO重叠服用的首推架构,比select和poll品质都要好,尤其是在有雅量不活跃接连的意况下。具体原理就不演说了,上面说说利用。

server.h

名词解释:man epoll之后,获得如下结果:

原地址:

有着有多个函数:

复制代码 代码如下:

NAME
       epoll – I/O event notification facility

第二对作者表示感谢,整理的很详细,读完受益匪浅!!!

#include <sys/epoll.h>

#ifndef SERVER_H
#define SERVER_H
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/epoll.h>
#include <signal.h>
#include <fcntl.h>
#include “bussiness.h”
#define LISTENTQ 5
#define DEF_PORT 6000
#define MAX_EPOLL_SIZE 10
#define DEF_PROCESS_NUM 5
int create_tcpsvr(char *ip, int port);
void fill_sockaddr(struct sockaddr_in *addr,char *ip, int port);
void comm_to_client(int sockfd);
void epoll_business(int epollfd, int listenfd, struct epoll_event
ev);
int init_epoll(int listenfd);
void create_process(int sockfd, int i);
#endif

SYNOPSIS
       #include <sys/epoll.h>

一).Epoll 介绍

 

server.c

DESCRIPTION
       epoll is a variant of poll(2) that can be used either as Edge or
Level
       Triggered interface and scales well to large numbers of  watched 
fds.
       Three  system  calls  are provided to set up and control an epoll
set:
       epoll_create(2), epoll_ctl(2), epoll_wait(2).

Epoll 但是脚下在 Linux
下开辟大规模出现互连网程序的紧俏人物, Epoll 在 Linux2.陆内核中标准引进,和 select 相似,其实都 I/O
多路复用技能而已 
,并不曾什么秘密的。其实在
linux
下设计并发互联网程序,一向不缺少方法,比如典型的 Apache 模型( Process Per
Connection ,简称 PPC ), TPC ( Thread Per Connection )模型,以及
select 模型和 poll 模型,那为什么还要再引进 Epoll
那么些东东吧?这依然有得说说的 …

1、int epoll_create ( int size );

复制代码 代码如下:

       An epoll set is connected to a file descriptor created  by 
epoll_cre-
       ate(2).   Interest for certain file descriptors is then
registered via
       epoll_ctl(2).  Finally, the actual wait is started by
epoll_wait(2).

二). 常用模型的缺点

size是epoll要监视的fd的框框。

#include “server.h”
/*
 * Create a TCP Server
 * Return socketfd
 */
int create_tcpsvr(char *ip,int port)
{
    int sockfd;
    struct sockaddr_in addr;

实际,1切的说明都是多余的,根据本人日前的摸底,EPOLL模型如同唯有一种格式,所以大家只要参考笔者上面的代码,就能够对EPOLL有所精晓了,代码的表达都曾经在讲解中:

假诺不摆出来其余模型的瑕疵,怎么能对照出 Epoll 的助益呢。

 

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == EOF){
        perror(“create_tcpsvr(),socket()”);
        exit(EXIT_FAILURE);
    }

while (TRUE)
 {
  int nfds = epoll_wait (m_epoll_fd, m_events, MAX_EVENTS,
EPOLL_TIME_OUT);//等待EPOLL时间的发生,相当于监听,至于有关的端口,须求在初阶化EPOLL的时候绑定。
  if (nfds <= 0)
   continue;
  m_bOnTimeChecking = FALSE;
  G_CurTime = time(NULL);
  for (int i=0; i<nfds; i++)
  {
   try
   {
    if (m_events[i].data.fd ==
m_listen_http_fd)//假若新监测到3个HTTP用户连接到绑定的HTTP端口,建立新的一连。由于大家新利用了SOCKET连接,所以基本没用。
    {
     OnAcceptHttpEpoll ();
    }
    else if (m_events[i].data.fd ==
m_listen_sock_fd)//要是新监测到3个SOCKET用户连接到了绑定的SOCKET端口,建立新的接连。
    {
     OnAcceptSockEpoll ();
    }
    else if (m_events[i].events &
EPOLLIN)//倘若是已经一而再的用户,并且吸收接纳数额,那么举办读入。
    {
     OnReadEpoll (i);
    }

① PPC/TPC 模型

2、int epoll_ctl ( int epfd, int op, int fd, struct epoll_event
*event );

    fill_sockaddr(&addr,ip,port);

    OnWriteEpoll (i);//查看当前的活动总是是还是不是有亟待写出的数目。
   }
   catch (int)
   {
    P瑞虎INTF (“CATCH捕获错误/n”);
    continue;
   }
  }
  m_bOnTimeChecking = TRUE;
  OnTimer ();//实行壹些定时的操作,首要就是删除1些短线用户等。
 }

那三种模型思想周边,正是让每三个赶来的总是一边自个儿工作去,别再来烦笔者 。只是
PPC 是为它开了二个历程,而 TPC
开了贰个线程。不过别烦小编是有代价的,它要时刻和空间呀,连接多了之后,那么多的长河
/
线程切换,那花费就上来了;由此这类模型能承受的最哈拉雷接数都不会高,1般在几百个左右。

(1)epfd:epoll_create的重返值。

    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == EOF){
        perror(“create_tcpsvr(),bind()”);
        exit(EXIT_FAILURE);
    }

 其实EPOLL的精髓,依照我当下的理解,也正是上述的几段短短的代码,看来时代真的分化了,此前怎么着接受多量用户连接的标题,今后却被如此轻巧的化解,真是令人只可以感慨。

② select 模型

(二)op  钦定操作类型:

    if (listen(sockfd,LISTENTQ) == EOF) {
        perror(“create_tcpsvr(),bind()”);
        exit(EXIT_FAILURE);
    }
澳门金沙国际,    return sockfd;
}

明日搞了壹天的epoll,想做1个高并发的代理程序。刚开首真是郁闷,平素搞不通,网上也有几篇介绍epoll的稿子。但都不长远,未有将壹部分留意的地点表明。以至于走了成都百货上千弯路,现将团结的一些精晓共享给大家,以少走弯路。 

  1. 最大并发数限制,因为1个进度所张开的 FD (文件讲述符)是有限定的,由
    FD_SETSIZE 设置,暗中认可值是 1024/204八 ,因而 Select
    模型的最大并发数就被相应限制了。本人改改这一个 FD_SETSIZE
    ?想法虽好,但是先看看上边吧 …

  2. 频率难点, select 每一回调用都会线性扫描全体的 FD
    集合,那样效能就会表现线性下跌,把 FD_SETSIZE
    改大的结局正是,我们都慢慢来,什么?都超时了。

  3. 基本 / 用户空间
    内部存款和储蓄器拷贝难题,怎么着让内核把 FD
    信息文告给用户空间啊?在那几个难点上
    select 选拔了内部存款和储蓄器拷贝方法。

     EPOLL_CTL_ADD:以前的事件表中注册fd上的事件

/**
 * Set TCP server’s address
 */
void fill_sockaddr(struct sockaddr_in *addr, char *ip, int port)
{
    assert(addr);

epoll用到的有着函数都以在头文件sys/epoll.h中宣称,有如何地点不精通或函数忘记了足以去看一下。 
epoll和select比较,最大差别在于: 

总结为:1.连接数受限 
2.搜寻配对速度慢 3.数量由基本拷贝到用户态

     EPOLL_CTL_MOD:修改fd上的注册事件

    addr -> sin_family = AF_INET;
    addr -> sin_port = htons(port?port:DEF_PORT);
    if (ip == NULL) {
        addr -> sin_addr.s_addr = htonl(INADDR_ANY);
    } else if((addr -> sin_addr.s_addr = inet_addr(ip)) == EOF)
{
       perror(“fill_sockaddr(),inet_addr()”);
       exit(EXIT_FAILURE);
    }
}
/*
 * Communicate to client
 */
void comm_to_clt(int listenfd)
{   
    printf(“TCP SERVER IS WAITING!\n”);

1epoll回来时曾经料定的掌握哪些sokcet
fd产生了轩然大波,不用再贰个个比对。那样就拉长了功用。 
2select的FD_SETSIZE是有限止的,而epoll是从未尽头的只与系统能源有关。 

③ poll 模型

     EPOLL_CTL_DEL:删除fd上的注册事件

    struct epoll_event events[MAX_EPOLL_SIZE];
    int fd_num;

1、epoll_create函数
函数注明:int epoll_create(int size)
该函数生成二个epoll专用的文件讲述符。它事实上是在基础申请1空中,用来存放你想关切的socket
fd上是还是不是产生以及发生了什么风浪。size就是你在这几个epoll
fd上能关怀的最大socket
fd数。随你定好了。只要你有空中。可参见上面与select之不相同贰. 

大致效用和 select 是同样的, select 缺点的 二 和 3 它都尚未改掉。

(叁)fd:要操作的公文讲述符(socket)

    int epollfd = init_epoll(listenfd);

22、epoll_ctl函数 
函数评释:int epoll_ctl(int epfd, int op, int fd, struct epoll_event
*event) 
该函数用于调节有个别epoll文件讲述符上的风云,能够注册事件,修改事件,删除事件。 
参数: 
epfd:由 epoll_create 生成的epoll专用的文件讲述符; 
op:要开始展览的操作例如登记事件,也许的取值EPOLL_CTL_ADD
注册、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 删除 

三). Epoll 的提升

 (四)event:钦定要监听fd的什么样事情。它是epoll_event结构指针类型:

    while (1) {

fd:关联的公文讲述符; 
event:指向epoll_event的指针; 
只要调用成功重回0,不成功再次回到-1 

把其他模型每一种批判了弹指间,再来看看 Epoll 的改进之处吧,其实把 select
的缺点反过来那正是 Epoll 的优点了。

struct epoll_event

        fd_num = epoll_wait(epollfd,events,MAX_EPOLL_SIZE,-1);
        if (fd_num == EOF) {
            perror(“comm_to_clt(),epoll_wait()”);
            continue;
        }
        while (–fd_num >= 0) {
            epoll_business(epollfd, listenfd, events[fd_num]);
        }
    }   
}
/*
 * Initlization epoll
 */
int init_epoll(int listenfd)
{
    struct epoll_event ev;
    int epollfd;

用到的数据结构 
typedef union epoll_data { 
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t; 

1. Epoll
未有最大产出连接的限制,上限是最大能够张开文件的数目,那么些数字一般远大于
204八, 1般的话这些数额和系列内部存款和储蓄器关系十分大 ,具体多少能够 cat
/proc/sys/fs/file-max 察看。

{

    if((epollfd = epoll_create(MAX_EPOLL_SIZE)) == EOF) {
        perror(“init_epoll(),epoll_create()”);
        exit(EXIT_FAILURE);
    }

struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};

二. 作用进步, Epoll
最大的长处就在于它只管你“活跃”的连接 ,而跟连接总量非亲非故,因而在实际上的网络环境中,
Epoll 的频率就会远远不止 select 和 poll 。

c语言多进度tcp服务器示例,epoll整理总计。     __unit32_t events;    // epoll事件

    ev.events = EPOLLIN;
    ev.data.fd = listenfd;
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD,listenfd, &ev)) {
        perror(“init_epoll(),epoll_ctl()”);
        exit(EXIT_FAILURE);
    }
    return epollfd;
}

如: 
struct epoll_event ev;
//设置与要拍卖的事件相关的文件讲述符
ev.data.fd=listenfd;
//设置要处理的事件类型
ev.events=EPOLLIN|EPOLLET;
//注册epoll事件
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

3. 内部存款和储蓄器拷贝, Epoll
在那点上选用了“共享内存 ”,这几个内存拷贝也轻易了。

     epoll_data_t data;     // 用户数量

/*
 * Respond for io change
 */
void epoll_business(int epollfd, int listenfd, struct epoll_event
ev)
{
    struct epoll_event ev_n;
    if (ev.data.fd == listenfd) {
        int clt_fd = accept(listenfd, 0, 0);
        if (clt_fd == EOF) {
            perror(“epoll_business(), accept()”);
            return;
        }

常用的风云类型:
EPOLLIN :表示对应的文件讲述符能够读;
EPOLLOUT:表示对应的公文讲述符能够写;
EPOLLPKoleosI:表示对应的文本讲述符有紧迫的数据可读
EPOLLEEvoqueWrangler:表示对应的文书讲述符产生错误;
EPOLLHUP:表示对应的公文讲述符被挂断;
EPOLLET:表示对应的文本讲述符有事件发生;

 肆). Epoll 为啥高效

};

        fcntl(clt_fd, F_SETFL, O_NONBLOCK);
        ev_n.events = EPOLLIN|EPOLLET;
        ev_n.data.fd = clt_fd;
        if (epoll_ctl(epollfd,EPOLL_CTL_ADD, clt_fd, &ev_n) == EOF)
{
            perror(“epoll_business(), epoll_ctl()”);
            return;
        }
    }else {
        main_service(ev.data.fd);
        if (epoll_ctl(epollfd,EPOLL_CTL_DEL, ev.data.fd, &ev) == EOF)
{
            perror(“epoll_business(), epoll_ctl()”);
        }
        close(ev.data.fd);
    }
}
/*
 * Create some process
 */

3、epoll_wait函数
函数表明:int epoll_wait(int epfd,struct epoll_event * events,int
maxevents,int timeout)
该函数用于轮询I/O事件的产生;
参数:
epfd:由epoll_create 生成的epoll专用的公文讲述符;
epoll_event:用于回传代处管事人件的数组;
maxevents:每一次能处理的轩然大波数;
timeout:等待I/O事件时有发生的超时值(单位自个儿也不太通晓);-一一定于阻塞,0一定于非阻塞。壹般用-一就可以
归来发惹祸件数。

Epoll
的连忙和其数据结构的安插性是密不可分的,那一个下面就会涉嫌。

events:描述事件类型。events能够是以下多少个宏的集结:

void create_process(int sockfd, int i)
{
    /*
     * Avoid zombie process
     */
    signal(SIGCHLD,SIG_IGN);

 

率先想起一下 select 模型,当有 I/O 事件来一时半刻, select
文告应用程序有事件到了快去处理,而应用程序必须轮询全部的 FD
集合,测试各类 FD
是不是有事件发生,并处管事人件;代码像上面那样:

 EPOLLIN :表示对应的文书讲述符能够读(包涵对端SOCKET符合规律关闭);
EPOLLOUT:表示对应的文书讲述符能够写;

    while (i–) {
        if (fork() == 0) {
            comm_to_clt(sockfd);
        }
    }
    while(1){
        sleep(100);
    }
}
int main(int argc, char *argv[])
{
    int sockfd = create_tcpsvr(0, 0);
    create_process(sockfd,DEF_PROCESS_NUM);
    exit(EXIT_SUCCESS);
}

 

[cpp] view
plain
copy

 EPOLLP奇骏I:表示对应的文件讲述符有迫切的数码可读(那里应该代表有带外数据来临);
EPOLLE奥迪Q5Tiguan:表示对应的文书讲述符发生错误;

bussiness.h

 

print?

EPOLLHUP:表示对应的文件讲述符被挂断;

复制代码 代码如下:

 

  1. int res = select(maxfd+1, &readfds, NULL, NULL, 120);  
  2. if (res > 0)  
  3. {  
  4.     for (int i = 0; i < MAX_CONNECTION; i++)  
  5.     {  
  6.         if (FD_ISSET(allConnection[i], &readfds))  
  7.         {  
  8.             handleEvent(allConnection[i]);  
  9.         }  
  10.     }  
  11. }  
  12. // if(res == 0) handle timeout, res < 0 handle error  

    int res = select(maxfd+1, &readfds, NULL, NULL, 120);
    if (res > 0)
    {

    for (int i = 0; i < MAX_CONNECTION; i++)
    {
        if (FD_ISSET(allConnection[i], &readfds))
        {
            handleEvent(allConnection[i]);
        }
    }
    

    }
    // if(res == 0) handle timeout, res < 0 handle error

 EPOLLET: 将EPOLL设为边缘触发(艾德ge
Triggered)情势,那是对峙于水平触发(Level Triggered)来讲的。

#ifndef BUSSINESS_H
#define BUSSINESS_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#define BUFF_SIZE 4096
void main_service(int sockfd);
int write_sock(int sockfd, char *buff, size_t length);
int read_sock(int sockfd, char *buff, size_t llength);
#endif

[java] view
plaincopy

Epoll
不仅会告诉应用程序有I/0
事件来临,还会告知应用程序相关的新闻,这几个音信是应用程序填充的,由此依照那个音信应用程序就能间接固定到事件,而不用遍历整个FD
集合。

EPOLLONESHOT:只监听一回事件,当监听完此番事件今后,假设还索要延续监听这几个socket的话,须要重新把那几个socket加入到EPOLL队列里。

bussiness.c

 

[cpp] view
plain
copy

data成员:在这之中data.fd常用来装要操作的fd。

复制代码 代码如下:

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <errno.h>  
  4. #include <string.h>  
  5. #include <sys/types.h>  
  6. #include <netinet/in.h>  
  7. #include <sys/socket.h>  
  8. #include <sys/wait.h>  
  9. #include <unistd.h>  
  10. #include <arpa/inet.h>  
  11. #include <openssl/ssl.h>  
  12. #include <openssl/err.h>  
  13. #include <fcntl.h>  
  14. #include <sys/epoll.h>  
  15. #include <sys/time.h>  
  16. #include <sys/resource.h>  

print?

 

#include “bussiness.h”

[java] view
plaincopy

  1. int res = epoll_wait(epfd, events, 20, 120);  
  2. for (int i = 0; i < res;i++)  
  3. {  
  4.     handleEvent(events[n]);  
  5. }  

    int res = epoll_wait(epfd, events, 20, 120);
    for (int i = 0; i < res;i++) {

    handleEvent(events[n]);
    

    }

typedef union epoll_data

void main_service(int sockfd)
{
    char buff[BUFF_SIZE];
    size_t buff_len;
    if ((buff_len = read_sock(sockfd, buff, BUFF_SIZE)) == EOF) {
        perror(“main_service(),read_sock()”);
        return;
    } else {
  //业务逻辑从那边先导
        printf(“%s”, buff);
    }

 

五).
Epoll 关键数据结构

{

}
/*
 * Recive messages
 * Return the length
 */
int read_sock(int sockfd, char *buff, size_t length)
{
    assert(buff);
    return read(sockfd, buff, length);
}
/*
 * Send messages
 * Return the length
 */
int write_sock(int sockfd, char *buff,size_t length)
{
    assert(buff);
    return write(sockfd, buff, length);
}

  1. #define MAXBUF 1024  
  2. #define MAXEPOLLSIZE 10000  

如今提到 Epoll 速度快和其数据结构密不可分,其重大数据结构正是:

     void *ptr;

您恐怕感兴趣的稿子:

  • C语言编写Linux守护进度实例
  • Linux中应用C语言的fork()函数成立子进度的实例教程
  • 比方讲授C语言的fork()函数成立子进度的用法
  • C语言达成在windows服务中新建进程的点子
  • 用c语言达成HUP时域信号重启进度的法门
  • Linux下C语言修改进程名称的艺术
  • C语言中安装进程优先顺序的格局
  • C语言中操作进程功率信号的连带函数使用详解
  • C语言怎么获得进度的PE文件消息
  • Linux下C语言的fork()子进度函数用法及连锁主题材料分析
  • C语言中赢得进程识别码的相干函数
  • C语言达成查看进度是还是不是留存的法子言传身教

[java] view
plaincopy

[cpp] view
plain
copy

      int fd;

 

print?

      __uint32_t u32;

  1. /* 
  2. setnonblocking – 设置句柄为非阻塞格局 
  3. */  
  4. int setnonblocking(int sockfd)  
  5. {  
  6.     if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)  
  7.  {  
  8.         return -1;  
  9.     }  
  10.     return 0;  
  11. }  
  1. struct epoll_event {  
  2.     __uint32_t events;      // Epoll events  
  3.     epoll_data_t data;      // User data variable  
  4. };  
  5. typedef union epoll_data {  
  6.     void *ptr;  
  7.     int fd;  
  8.     __uint32_t u32;  
  9.     __uint64_t u64;  
  10. } epoll_data_t;  

    struct epoll_event {

    __uint32_t events;      // Epoll events
    epoll_data_t data;      // User data variable
    

    };
    typedef union epoll_data {

    void *ptr;
    int fd;
    __uint32_t u32;
    __uint64_t u64;
    

    } epoll_data_t;

      __uint64_t u64;

[java] view
plaincopy

可见
epoll_data 是三个 union 结构体 , 借助于它应用程序能够保留多数类别的音信:fd 、指针等等。有了它,应用程序就能够一向定位目标了。

  } epoll_data_t;

 

六). 使用 Epoll

 

  1. /* 
  2. handle_message – 处理各个 socket 上的消息收发 
  3. */  
  4. int handle_message(int new_fd)  
  5. {  
  6.     char buf[MAXBUF + 1];  
  7.     int len;  
  8.       
  9.  /* 发轫拍卖每一个新连接上的多寡收发 */  
  10.     bzero(buf, MAXBUF + 1);  
  11.      
  12.  /* 接收客户端的音讯 */  
  13.     len = recv(new_fd, buf, MAXBUF, 0);  
  14.     if (len > 0)  
  15.  {  
  16.         printf  
  17.             (“%d接收消息成功:’%s’,共%d个字节的多少/n”,  
  18.              new_fd, buf, len);  
  19.  }  
  20.     else  
  21.  {  
  22.         if (len < 0)  
  23.      printf  
  24.                 (“音信接收退步!错误代码是%d,错误音信是’%s’/n”,  
  25.                  errno, strerror(errno));  
  26.         close(new_fd);  
  27.         return -1;  
  28.     }  
  29.     /* 处理每一个新连接上的数额收发结束 */  
  30.     return len;  
  31. }  
  32. /************至于本文书档案******************************************** 
  33. *filename: epoll-server.c 
  34. *purpose: 演示epoll处理海量socket连接的艺术 
  35. *wrote by: zhoulifa(<a href=”mailto:zhoulifa@163.com”>zhoulifa@163.com</a>) 周立发(<a href=”;) 
  36. Linux爱好者 Linux知识传播者 SOHO族 开垦者 最擅长C语言 
  37. *date time:2007-01-31 21:00 
  38. *Note: 任何人能够随心所欲复制代码并动用那个文书档案,当然包蕴你的小购销用途 
  39. * 但请依据GPL 
  40. *Thanks to:Google 
  41. *霍普:希望越多的人奉献本身的力量,为科学技能发展效劳 
  42. * 科技(science and technology)站在巨人的双肩上发展越来越快!感激有开源前辈的贡献! 
  43. *********************************************************************/  
  44. int main(int argc, char **argv)  
  45. {  
  46.     int listener, new_fd, kdpfd, nfds, n, ret, curfds;  
  47.     socklen_t len;  
  48.     struct sockaddr_in my_addr, their_addr;  
  49.     unsigned int myport, lisnum;  
  50.     struct epoll_event ev;  
  51.     struct epoll_event events[MAXEPOLLSIZE];  
  52.     struct rlimit rt;  
  53.  myport = 5000;  
  54.  lisnum = 2;   
  55.       
  56.  /* 设置各种进程允许展开的最大文件数 */  
  57.     rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;  
  58.     if (setrlimit(RLIMIT_NOFILE, &rt) == -1)   
  59.  {  
  60.         perror(“setrlimit”);  
  61.         exit(1);  
  62.     }  
  63.     else   
  64.     {  
  65.         printf(“设置系统能源参数成功!/n”);  
  66.     }  

既然 Epoll 比较 select 这么好,那么用起来何等呢?会不会很麻烦啊 …
先看看下边的几个函数吧,就了然 Epoll 的易用了。 

 

[java] view
plaincopy

int epoll_create(int size);
 

3、int epoll_wait ( int epfd, struct epoll_event* events, int
maxevents, int timeout );

 

转换一个Epoll 专用的文书描述符,其实是申请3个基础空间,用来存放你想关怀的
socket fd 上是还是不是爆发以及发生了怎么风云。 size 正是你在那几个 Epoll fd
上能尊敬的最大 socket fd 数,大小自定,只要内存充足。

epoll_wait的干活流程是:等待,借使有epoll事件时有产生登时回去,不然等待timeout皮秒。再次回到时拷贝要处理的风浪到events指向的数组,重回就绪的文本讲述符的个数,退步时回来-一并设置errno。 

  1.     /* 开启 socket 监听 */  
  2.     if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)  
  3.     {  
  4.         perror(“socket”);  
  5.         exit(1);  
  6.     }  
  7.     else  
  8.     {  
  9.         printf(“socket 创设成功!/n”);  
  10.  }  
  11.    
  12.     setnonblocking(listener);  

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event );
 

timeout:钦命epoll的逾期时间,单位是阿秒。当timeout为-壹是,epoll_wait调用将永世阻塞,直到有些事件产生。当timeout为0时,epoll_wait调用将登时回到。 

[java] view
plaincopy

调节某些Epoll 文件讲述符上的事件:注册、修改、删除。个中参数 epfd 是
epoll_create() 创造 Epoll 专用的文本讲述符。相对于 select 模型中的
FD_SET 和 FD_CLR 宏。

maxevents:钦点最多监听多少个事件。若是events指向的是十多少个单元的布局体数组,那么就安装maxevents为20。 

 

int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);
 

events:
events指向的数组军长拷贝全部就绪的轩然大波,从根才能件表中。events的积极分子是struct
epoll_event类型,一般包蕴events(其值是如:EPOLLIN、EPOLLOUT等)。还有一个是data.fd,包括拷贝的轩然大波对应的socket,假若是服务器监听socket,表达是有用户连接到这么些socket,如若是别的已经三番五次好的socket,表明是有数据要发送恐怕吸收。

  1.     bzero(&my_addr, sizeof(my_addr));  
  2.     my_addr.sin_family = PF_INET;  
  3.     my_addr.sin_port = htons(myport);  
  4.     my_addr.sin_addr.s_addr = INADDR_ANY;  

等候 I/O 事件的产生;参数表明:

假诺事件数组中的数据获得处理,那么内核事件表中的风云就会被剔除,下次wait就从不这一个socket的轩然大波了。 

[java] view
plaincopy

epfd: 由 epoll_create() 调换的 Epoll 专用的文书讲述符;

 

 

epoll_event: 用于回传代处监护人件的数组;

实例代码:

  1.     if (bind(listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1)   
  2.     {  
  3.         perror(“bind”);  
  4.         exit(1);  
  5.     }   
  6.     else  
  7.     {  
  8.         printf(“IP 地址和端口绑定成功/n”);  
  9.  }  
  10.     if (listen(listener, lisnum) == -1)   
  11.     {  
  12.         perror(“listen”);  
  13.         exit(1);  
  14.     }  
  15.     else  
  16.     {  
  17.         printf(“开启服务成功!/n”);  
  18.  }  
  19.       
  20.  /* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */  
  21.     kdpfd = epoll_create(MAXEPOLLSIZE);  
  22.     len = sizeof(struct sockaddr_in);  
  23.     ev.events = EPOLLIN | EPOLLET;  
  24.     ev.data.fd = listener;  
  25.     if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0)   
  26.  {  
  27.         fprintf(stderr, “epoll set insertion error: fd=%d/n”, listener);  
  28.         return -1;  
  29.     }  
  30.  else  
  31.     {  
  32.   printf(“监听 socket 加入 epoll 成功!/n”);  
  33.  }  
  34.     curfds = 1;  
  35.     while (1)   
  36.  {  
  37.         /* 等待有事件产生 */  
  38.         nfds = epoll_wait(kdpfd, events, curfds, -1);  
  39.         if (nfds == -1)  
  40.   {  
  41.             perror(“epoll_wait”);  
  42.             break;  
  43.         }  
  44.         /* 处理全体事件 */  
  45.         for (n = 0; n < nfds; ++n)  
  46.   {  
  47.             if (events[n].data.fd == listener)   
  48.    {  
  49.                 new_fd = accept(listener, (struct sockaddr *) &their_addr,&len);  
  50.                 if (new_fd < 0)   
  51.     {  
  52.                     perror(“accept”);  
  53.                     continue;  
  54.                 }   
  55.     else  
  56.     {  
  57.      printf(“有连接来自于: %d:%d, 分配的 socket 为:%d/n”,  
  58.                              inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);  
  59.     }  
  60.                 setnonblocking(new_fd);  
  61.                 ev.events = EPOLLIN | EPOLLET;  
  62.                 ev.data.fd = new_fd;  
  63.                 if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, new_fd, &ev) < 0)  
  64.     {  
  65.                     fprintf(stderr, “把 socket ‘%d’ 加入 epoll 失败!%s/n”,  
  66.                             new_fd, strerror(errno));  
  67.                     return -1;  
  68.                 }  
  69.                 curfds++;  
  70.             }   
  71.    else  
  72.    {  
  73.                 ret = handle_message(events[n].data.fd);  
  74.                 if (ret < 1 && errno != 11)  
  75.     {  
  76.                     epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev);  
  77.                     curfds–;  
  78.                 }  
  79.             }  
  80.         }  
  81.     }  
  82.     close(listener);  
  83.     return 0;  
  84. }  

maxevents: 每一次能处理的事件数;

epoll.c

 epoll_wait运转的原理是 等侍注册在epfd上的socket
fd的事件的发生,借使发生则将产生的sokct fd和事件类型放入到events数组中。
并且将登记在epfd上的socket
fd的轩然大波类型给清空,所以借使下2个循环你还要关怀这么些socket
fd的话,则需求用epoll_ctl(epfd,EPOLL_CTL_MOD,listenfd,&ev)来重新初始化socket
fd的事件类型。那时不用EPOLL_CTL_ADD,因为socket
fd并未清空,只是事件类型清空。这一步非凡关键。 

timeout: 等待 I/O 事件产生的超时值;

#include <stdio.h>

 

回去发闹事件数。

#include <sys/epoll.h>

二、第三个示范:

周旋于 select 模型中的 select 函数。

#include <sys/socket.h>

 

7). 例子程序

#include <stdlib.h>

  1. Epoll是何方神圣?

上面是一个简练 Echo Server
的例子程序,麻雀虽小,伍脏俱全,还包括了三个轻松易行的过期检查体制,简洁起见未有做错误处理。

#include <netinet/in.h>                 //包含sockaddr_in定义

Epoll不过脚下在Linux下支付大规模出现互联网程序的热点人选,Epoll 在Linux二.陆内核中正式引进,和select相似,其实都I/O多路复用本领而已,并不曾什么秘密的。

[cpp] view
plain
copy

#include <errno.h>

实际上在Linux下设计并发互联网程序,一直不缺乏方法,比如典型的Apache模型(Process
Per Connection,简称PPC),TPC(Thread
PerConnection)模型,以及select模型和poll模型,这怎么还要再引进Epoll这么些东东啊?这依旧有得说说的…

print?

#include <string.h>                     //包含memset strncpy

贰. 常用模型的短处

  1. //   
  2. // a simple echo server using epoll in linux  
  3. //   
  4. // 2009-11-05  
  5. // by sparkling  
  6. //   
  7. #include <sys/socket.h>  
  8. #include <sys/epoll.h>  
  9. #include <netinet/in.h>  
  10. #include <arpa/inet.h>  
  11. #include <fcntl.h>  
  12. #include <unistd.h>  
  13. #include <stdio.h>  
  14. #include <errno.h>  
  15. #include <iostream>  
  16. using namespace std;  
  17. #define MAX_EVENTS 500  
  18. struct myevent_s  
  19. {  
  20.     int fd;  
  21.     void (*call_back)(int fd, int events, void *arg);  
  22.     int events;  
  23.     void *arg;  
  24.     int status; // 1: in epoll wait list, 0 not in  
  25.     char buff[128]; // recv data buffer  
  26.     int len;  
  27.     long last_active; // last active time  
  28. };  
  29. // set event  
  30. void EventSet(myevent_s *ev, int fd, void (*call_back)(int, int, void*), void *arg)  
  31. {  
  32.     ev->fd = fd;  
  33.     ev->call_back = call_back;  
  34.     ev->events = 0;  
  35.     ev->arg = arg;  
  36.     ev->status = 0;  
  37.     ev->last_active = time(NULL);  
  38. }  
  39. // add/mod an event to epoll  
  40. void EventAdd(int epollFd, int events, myevent_s *ev)  
  41. {  
  42.     struct epoll_event epv = {0, {0}};  
  43.     int op;  
  44.     epv.data.ptr = ev;  
  45.     epv.events = ev->events = events;  
  46.     if(ev->status == 1){  
  47.         op = EPOLL_CTL_MOD;  
  48.     }  
  49.     else{  
  50.         op = EPOLL_CTL_ADD;  
  51.         ev->status = 1;  
  52.     }  
  53.     if(epoll_ctl(epollFd, op, ev->fd, &epv) < 0)  
  54.         printf(“Event Add failed[fd=%d]/n”, ev->fd);  
  55.     else  
  56.         printf(“Event Add OK[fd=%d]/n”, ev->fd);  
  57. }  
  58. // delete an event from epoll  
  59. void EventDel(int epollFd, myevent_s *ev)  
  60. {  
  61.     struct epoll_event epv = {0, {0}};  
  62.     if(ev->status != 1) return;  
  63.     epv.data.ptr = ev;  
  64.     ev->status = 0;  
  65.     epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &epv);  
  66. }  
  67. int g_epollFd;  
  68. myevent_s g_Events[MAX_EVENTS+1]; // g_Events[MAX_EVENTS] is used by listen fd  
  69. void RecvData(int fd, int events, void *arg);  
  70. void SendData(int fd, int events, void *arg);  
  71. // accept new connections from clients  
  72. void AcceptConn(int fd, int events, void *arg)  
  73. {  
  74.     struct sockaddr_in sin;  
  75.     socklen_t len = sizeof(struct sockaddr_in);  
  76.     int nfd, i;  
  77.     // accept  
  78.     if((nfd = accept(fd, (struct sockaddr*)&sin, &len)) == -1)  
  79.     {  
  80.         if(errno != EAGAIN && errno != EINTR)  
  81.         {  
  82.             printf(“%s: bad accept”, __func__);  
  83.         }  
  84.         return;  
  85.     }  
  86.     do  
  87.     {  
  88.         for(i = 0; i < MAX_EVENTS; i++)  
  89.         {  
  90.             if(g_Events[i].status == 0)  
  91.             {  
  92.                 break;  
  93.             }  
  94.         }  
  95.         if(i == MAX_EVENTS)  
  96.         {  
  97.             printf(“%s:max connection limit[%d].”, __func__, MAX_EVENTS);  
  98.             break;  
  99.         }  
  100.         // set nonblocking  
  101.         if(fcntl(nfd, F_SETFL, O_NONBLOCK) < 0) break;  
  102.         // add a read event for receive data  
  103.         EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);  
  104.         EventAdd(g_epollFd, EPOLLIN|EPOLLET, &g_Events[i]);  
  105.         printf(“new conn[%s:%d][time:%d]/n”, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), g_Events[i].last_active);  
  106.     }while(0);  
  107. }  
  108. // receive data  
  109. void RecvData(int fd, int events, void *arg)  
  110. {  
  111.     struct myevent_s *ev = (struct myevent_s*)arg;  
  112.     int len;  
  113.     // receive data  
  114.     len = recv(fd, ev->buff, sizeof(ev->buff)-1, 0);    
  115.     EventDel(g_epollFd, ev);  
  116.     if(len > 0)  
  117.     {  
  118.         ev->len = len;  
  119.         ev->buff[len] = ‘/0’;  
  120.         printf(“C[%d]:%s/n”, fd, ev->buff);  
  121.         // change to send event  
  122.         EventSet(ev, fd, SendData, ev);  
  123.         EventAdd(g_epollFd, EPOLLOUT|EPOLLET, ev);  
  124.     }  
  125.     else if(len == 0)  
  126.     {  
  127.         close(ev->fd);  
  128.         printf(“[fd=%d] closed gracefully./n”, fd);  
  129.     }  
  130.     else  
  131.     {  
  132.         close(ev->fd);  
  133.         printf(“recv[fd=%d] error[%d]:%s/n”, fd, errno, strerror(errno));  
  134.     }  
  135. }  
  136. // send data  
  137. void SendData(int fd, int events, void *arg)  
  138. {  
  139.     struct myevent_s *ev = (struct myevent_s*)arg;  
  140.     int len;  
  141.     // send data  
  142.     len = send(fd, ev->buff, ev->len, 0);  
  143.     ev->len = 0;  
  144.     EventDel(g_epollFd, ev);  
  145.     if(len > 0)  
  146.     {  
  147.         // change to receive event  
  148.         EventSet(ev, fd, RecvData, ev);  
  149.         EventAdd(g_epollFd, EPOLLIN|EPOLLET, ev);  
  150.     }  
  151.     else  
  152.     {  
  153.         close(ev->fd);  
  154.         printf(“recv[fd=%d] error[%d]/n”, fd, errno);  
  155.     }  
  156. }  
  157. void InitListenSocket(int epollFd, short port)  
  158. {  
  159.     int listenFd = socket(AF_INET, SOCK_STREAM, 0);  
  160.     fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking  
  161.     printf(“server listen fd=%d/n”, listenFd);  
  162.     EventSet(&g_Events[MAX_EVENTS], listenFd, AcceptConn, &g_Events[MAX_EVENTS]);  
  163.     // add listen socket  
  164.     EventAdd(epollFd, EPOLLIN|EPOLLET, &g_Events[MAX_EVENTS]);  
  165.     // bind & listen  
  166.     sockaddr_in sin;  
  167.     bzero(&sin, sizeof(sin));  
  168.     sin.sin_family = AF_INET;  
  169.     sin.sin_addr.s_addr = INADDR_ANY;  
  170.     sin.sin_port = htons(port);  
  171.     bind(listenFd, (const sockaddr*)&sin, sizeof(sin));  
  172.     listen(listenFd, 5);  
  173. }  
  174. int main(int argc, char **argv)  
  175. {  
  176.     short port = 12345; // default port  
  177.     if(argc == 2){  
  178.         port = atoi(argv[1]);  
  179.     }  
  180.     // create epoll  
  181.     g_epollFd = epoll_create(MAX_EVENTS);  
  182.     if(g_epollFd <= 0) printf(“create epoll failed.%d/n”, g_epollFd);  
  183.     // create & bind listen socket, and add to epoll, set non-blocking  
  184.     InitListenSocket(g_epollFd, port);  
  185.     // event loop  
  186.     struct epoll_event events[MAX_EVENTS];  
  187.     printf(“server running:port[%d]/n”, port);  
  188.     int checkPos = 0;  
  189.     while(1){  
  190.         // a simple timeout check here, every time 100, better to use a mini-heap, and add timer event  
  191.         long now = time(NULL);  
  192.         for(int i = 0; i < 100; i++, checkPos++) // doesn’t check listen fd  
  193.         {  
  194.             if(checkPos == MAX_EVENTS) checkPos = 0; // recycle  
  195.             if(g_Events[checkPos].status != 1) continue;  
  196.             long duration = now – g_Events[checkPos].last_active;  
  197.             if(duration >= 60) // 60s timeout  
  198.             {  
  199.                 close(g_Events[checkPos].fd);  
  200.                 printf(“[fd=%d] timeout[%d–%d]./n”, g_Events[checkPos].fd, g_Events[checkPos].last_active, now);  
  201.                 EventDel(g_epollFd, &g_Events[checkPos]);  
  202.             }  
  203.         }  
  204.         // wait for events to happen  
  205.         int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, 1000);  
  206.         if(fds < 0){  
  207.             printf(“epoll_wait error, exit/n”);  
  208.             break;  
  209.         }  
  210.         for(int i = 0; i < fds; i++){  
  211.             myevent_s *ev = (struct myevent_s*)events[i].data.ptr;  
  212.             if((events[i].events&EPOLLIN)&&(ev->events&EPOLLIN)) // read event  
  213.             {  
  214.                 ev->call_back(ev->fd, events[i].events, ev->arg);  
  215.             }  
  216.             if((events[i].events&EPOLLOUT)&&(ev->events&EPOLLOUT)) // write event  
  217.             {  
  218.                 ev->call_back(ev->fd, events[i].events, ev->arg);  
  219.             }  
  220.         }  
  221.     }  
  222.     // free resource  
  223.     return 0;  
  224. }   

    //
    // a simple echo server using epoll in linux
    //
    // 2009-11-05
    // by sparkling
    //
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    using namespace std;
    #define MAX_EVENTS 500
    struct myevent_s
    {
    int fd;
    void (call_back)(int fd, int events, void arg);
    int events;
    void arg;
    int status; // 1: in epoll wait list, 0 not in
    char buff[128]; // recv data buffer
    int len;
    long last_active; // last active time
    };
    // set event
    void EventSet(myevent_s
    ev, int fd, void (call_back)(int, int, void), void arg)
    {
    ev->fd = fd;
    ev->call_back = call_back;
    ev->events = 0;
    ev->arg = arg;
    ev->status = 0;
    ev->last_active = time(NULL);
    }
    // add/mod an event to epoll
    void EventAdd(int epollFd, int events, myevent_s
    ev)
    {
    struct epoll_event epv = {0, {0}};
    int op;
    epv.data.ptr = ev;
    epv.events = ev->events = events;
    if(ev->status == 1){

       op = EPOLL_CTL_MOD;
    

    }
    else{

       op = EPOLL_CTL_ADD;
       ev->status = 1;
    

    }
    if(epoll_ctl(epollFd, op, ev->fd, &epv) < 0)

       printf("Event Add failed[fd=%d]/n", ev->fd);
    

    else

       printf("Event Add OK[fd=%d]/n", ev->fd);
    

    }
    // delete an event from epoll
    void EventDel(int epollFd, myevent_s ev)
    {
    struct epoll_event epv = {0, {0}};
    if(ev->status != 1) return;
    epv.data.ptr = ev;
    ev->status = 0;
    epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &epv);
    }
    int g_epollFd;
    myevent_s g_Events[MAX_EVENTS+1]; // g_Events[MAX_EVENTS] is used by listen fd
    void RecvData(int fd, int events, void
    arg);
    void SendData(int fd, int events, void arg);
    // accept new connections from clients
    void AcceptConn(int fd, int events, void
    arg)
    {
    struct sockaddr_in sin;
    socklen_t len = sizeof(struct sockaddr_in);
    int nfd, i;
    // accept
    if((nfd = accept(fd, (struct sockaddr*)&sin, &len)) == -1)
    {

       if(errno != EAGAIN && errno != EINTR)
       {
           printf("%s: bad accept", __func__);
       }
       return;
    

    }
    do
    {

       for(i = 0; i < MAX_EVENTS; i++)
       {
           if(g_Events[i].status == 0)
           {
               break;
           }
       }
       if(i == MAX_EVENTS)
       {
           printf("%s:max connection limit[%d].", __func__, MAX_EVENTS);
           break;
       }
       // set nonblocking
       if(fcntl(nfd, F_SETFL, O_NONBLOCK) < 0) break;
       // add a read event for receive data
       EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);
       EventAdd(g_epollFd, EPOLLIN|EPOLLET, &g_Events[i]);
       printf("new conn[%s:%d][time:%d]/n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), g_Events[i].last_active);
    

    }while(0);
    }
    // receive data
    void RecvData(int fd, int events, void arg)
    {
    struct myevent_s
    ev = (struct myevent_s*)arg;
    int len;
    // receive data
    len = recv(fd, ev->buff, sizeof(ev->buff)-1, 0);
    EventDel(g_epollFd, ev);
    if(len > 0)
    {

       ev->len = len;
       ev->buff[len] = '/0';
       printf("C[%d]:%s/n", fd, ev->buff);
       // change to send event
       EventSet(ev, fd, SendData, ev);
       EventAdd(g_epollFd, EPOLLOUT|EPOLLET, ev);
    

    }
    else if(len == 0)
    {

       close(ev->fd);
       printf("[fd=%d] closed gracefully./n", fd);
    

    }
    else
    {

       close(ev->fd);
       printf("recv[fd=%d] error[%d]:%s/n", fd, errno, strerror(errno));
    

    }
    }
    // send data
    void SendData(int fd, int events, void arg)
    {
    struct myevent_s
    ev = (struct myevent_s*)arg;
    int len;
    // send data
    len = send(fd, ev->buff, ev->len, 0);
    ev->len = 0;
    EventDel(g_epollFd, ev);
    if(len > 0)
    {

       // change to receive event
       EventSet(ev, fd, RecvData, ev);
       EventAdd(g_epollFd, EPOLLIN|EPOLLET, ev);
    

    }
    else
    {

       close(ev->fd);
       printf("recv[fd=%d] error[%d]/n", fd, errno);
    

    }
    }
    void InitListenSocket(int epollFd, short port)
    {
    int listenFd = socket(AF_INET, SOCK_STREAM, 0);
    fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking
    printf(“server listen fd=%d/n”, listenFd);
    EventSet(&g_Events[MAX_EVENTS], listenFd, AcceptConn, &g_Events[MAX_EVENTS]);
    // add listen socket
    EventAdd(epollFd, EPOLLIN|EPOLLET, &g_Events[MAX_EVENTS]);
    // bind & listen
    sockaddr_in sin;
    bzero(&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(port);
    bind(listenFd, (const sockaddr*)&sin, sizeof(sin));
    listen(listenFd, 5);
    }
    int main(int argc, char **argv)
    {
    short port = 12345; // default port
    if(argc == 2){

       port = atoi(argv[1]);
    

    }
    // create epoll
    g_epollFd = epoll_create(MAX_EVENTS);
    if(g_epollFd <= 0) printf("create epoll failed.%d/n", g_epollFd); // create & bind listen socket, and add to epoll, set non-blocking InitListenSocket(g_epollFd, port); // event loop struct epoll_event events[MAX_EVENTS]; printf("server running:port[%d]/n", port); int checkPos = 0; while(1){

       // a simple timeout check here, every time 100, better to use a mini-heap, and add timer event
       long now = time(NULL);
       for(int i = 0; i < 100; i++, checkPos++) // doesn't check listen fd
       {
           if(checkPos == MAX_EVENTS) checkPos = 0; // recycle
           if(g_Events[checkPos].status != 1) continue;
           long duration = now - g_Events[checkPos].last_active;
           if(duration >= 60) // 60s timeout
           {
               close(g_Events[checkPos].fd);
               printf("[fd=%d] timeout[%d--%d]./n", g_Events[checkPos].fd, g_Events[checkPos].last_active, now);
               EventDel(g_epollFd, &g_Events[checkPos]);
           }
       }
       // wait for events to happen
       int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, 1000);
       if(fds < 0){
           printf("epoll_wait error, exit/n");
           break;
       }
       for(int i = 0; i < fds; i++){
           myevent_s *ev = (struct myevent_s*)events[i].data.ptr;
           if((events[i].events&EPOLLIN)&&(ev->events&EPOLLIN)) // read event
           {
               ev->call_back(ev->fd, events[i].events, ev->arg);
           }
           if((events[i].events&EPOLLOUT)&&(ev->events&EPOLLOUT)) // write event
           {
               ev->call_back(ev->fd, events[i].events, ev->arg);
           }
       }
    

    }
    // free resource
    return 0;

 

1旦不摆出来其余模型的通病,怎么能对照出Epoll的亮点呢。

3、epoll
3.1、poll(select)的限制
     
Poll函数源点于SV奇骏三,最初局限于流设备,SV普拉多四撤除了那种范围。总是来讲,poll比select要快快壹些,可是,它有可移植性难点,例如,windows就只协助select。
2个poll的简短例子:

 

2.1 PPC/TPC模型

澳门金沙国际 1代码

int main(int argc,char* argv[])   //主函数

那二种模型理念附近,便是让每3个过来的连接壹边本人职业去,别再来烦小编。只是PPC是为它开了3个进度,而TPC开了二个线程。可是别烦小编是有代价的,它要时空呀,连接多了后来,那么多的进度/线程切换,那开销就上来了;由此那类模型能接受的最都林接数都不会高,1般在几百个左右。

澳门金沙国际 2

{

2.2 select模型

#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#define TIMEOUT 5       /* poll timeout, in seconds */
int main (void)
{
        struct pollfd fds[2];
        int ret;
        /* watch stdin for input */
        fds[0].fd = STDIN_FILENO;
        fds[0].events = POLLIN;
        /* watch stdout for ability to write (almost always true) */
        fds[1].fd = STDOUT_FILENO;
        fds[1].events = POLLOUT;
        /* All set, block! */
        ret = poll (fds, 2, TIMEOUT * 1000);
        if (ret == -1) {
                perror (“poll”);
                return 1;
        }
        if (!ret) {
                printf (“%d seconds elapsed.\n”, TIMEOUT);
                return 0;
        }
        if (fds[0].revents & POLLIN)
                printf (“stdin is readable\n”);
        if (fds[1].revents & POLLOUT)
                printf (“stdout is writable\n”);
        return 0;
}

 

一. 最大并发数限制,因为二个进度所展开的FD(文件讲述符)是有限定的,由FD_SETSIZE设置,暗许值是拾24/204八,因而Select模型的最大并发数就被相应限制了。本身改改那几个FD_SETSIZE?想法虽好,不过先看看下边吧…

澳门金沙国际 3

      int epfd1;int result;

2. 频率难点,select每一趟调用都会线性扫描全体的FD集合,那样功效就会表现线性降低,把FD_SETSIZE改大的结果正是,大家都稳步来,什么?都超时了??!!

 

      int server_len,client_len;

叁. 基本/用户空间 内部存款和储蓄器拷贝难题,怎样让内核把FD消息公告给用户空间吗?在那么些标题上select选拔了内部存款和储蓄器拷贝方法。

    
select模型与此类例。内核必须遍历全体监视的描述符,而应用程序也务必遍历全部描述符,检查哪些描述符已经准备好。当描述符成都百货上千时,会变得相当低效——那是select(poll)模型低效的源于所在。思量那几个情形,二.陆后头的木本都推荐了epoll模型。

      int server_sockfd,client_sockfd;

2.3 poll模型

3.二、主题数据结构与接口
Epoll模型由二个函数构成,epoll_create、epoll_ctl和epoll_wait。
3.2.1创建epoll实例(Creating a New Epoll Instance)
     epoll环境经过epoll_create函数创制:
     #include <sys/epoll.h>
      int epoll_create (int size)
     
调用成功则赶回与实例关联的公文描述符,该文件讲述符与真正的文书并未有别的涉及,仅作为接下去调用的函数的句柄。size是给基础的贰个提示,告诉内核就要监视的文本讲述符的数额,它不是最大值;可是,传递合适的值能够抓实系统品质。发生错误时,再次回到-壹。
例子:

      struct sockaddr_in server_address;       //定义在
<netinet/in.h>

多数功效和select是千篇1律的,select缺点的二和3它都未曾改掉。

int epfd;
epfd = epoll_create (100);  /* plan to watch ~100 fds */
if (epfd < 0)
        perror (“epoll_create”);

      struct sockaddr_in client_address;

  1. Epoll的提升

3.2.2、控制epoll(Controlling Epoll)
通过epoll_ctl,可以参与文件讲述符到epoll环境或从epoll环境移除文件讲述符。

      struct epoll_event ev1;

把其他模型每一种批判了眨眼间间,再来看看Epoll的勘误之处吧,其实把select的缺陷反过来那便是Epoll的长处了。

澳门金沙国际 4代码

      struct epoll_event ev[20];

3.一.
Epoll从没有过最大产出连接的限定,上限是最大能够张开文件的数额,那么些数字1般远超越2048, 1般的话那么些数量和体系内部存储器关系十分大,具体数量能够cat
/proc/sys/fs/file-max察看。

澳门金沙国际 5

      int epollreturn;

3.二. 效能提高,Epoll最大的长处就在于它只管你“活跃”的总是,而跟连接总的数量非亲非故,因而在实际上的网络环境中,Epoll的频率就会远远超过select和poll。

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

      int i,j,res;

三.三. 内存拷贝,Epoll在这一点上行使了“共享内部存款和储蓄器”,这些内部存储器拷贝也差不多了。

struct epoll_event {
        _ _u32 events;  /* events */
        union {
                void *ptr;
                int fd;
                _ _u32 u32;
                _ _u64 u64;
        } data;
};

      int sockfd;

 

澳门金沙国际 6

      char ch = ‘0’;

 

 

      char buff[1024];

  1. Epoll为何高效

 

     

Epoll的短平快和其数据结构的设计是一环扣一环的,这一个下边就会涉嫌。

 

      server_address.sin_family = AF_INET;

第3次顾一下select模型,当有I/O事件来一时半刻,select通告应用程序有事件到了快去处理,而应用程序必须轮询全体的FD集合,测试各个FD是还是不是有事件发生,并处监护人件;代码像上边那样:

epfd为epoll_create重回的叙说符。op表示对描述符fd选拔的操作,取值如下:
EPOLL_CTL_ADD
Add a monitor on the file associated with the file descriptor fd to the
epoll instance associated with epfd, per the events defined in event.

      server_address.sin_addr.s_addr = inet_addr(“192.168.131.129”);

 

EPOLL_CTL_DEL
Remove a monitor on the file associated with the file descriptor fd from
the epollinstance associated with epfd.
EPOLL_CTL_MOD
Modify an existing monitor of fd with the updated events specified by
event.

      server_sockfd = socket(AF_INET,SOCK_STREAM,0);

int res = select(maxfd+1, &readfds, NULL, NULL, 120);

epoll_event结构中的events字段,表示对该公文讲述符所关怀的事件,它的取值如下:
EPOLLET
Enables edge-triggered behavior for the monitor of the file .The default
behavior is level-
triggered.
EPOLLHUP
A hangup occurred on the file. This event is always monitored, even if
it’s not specified.
EPOLLIN
The file is available to be read from without blocking.
EPOLLONESHOT
After an event is generated and read, the file is automatically no
longer monitored.A new event mask must be specified via EPOLL_CTL_MOD
to reenable the watch.
EPOLLOUT
The file is available to be written to without blocking.
EPOLLPRI
There is urgent out-of-band data available to read.
而epoll_event结构中的fd是epoll高效的来源于所在,当描述符准备好。应用程序不用遍历全数描述符,而只用检查发生事件的叙述符。
将贰个叙述符到场epoll环境:

      server_address.sin_port = htons(9734);

if(res > 0)

澳门金沙国际 7代码

      server_len = sizeof(server_address);

{

澳门金沙国际 8

      client_len = sizeof(client_address);

    for(int i = 0; i < MAX_CONNECTION; i++)

struct epoll_event event;
int ret;
event.data.fd = fd; /* return the fd to us later */
event.events = EPOLLIN | EPOLLOUT;
ret = epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &event);
if (ret)
        perror (“epoll_ctl”);

     

    {

澳门金沙国际 9

      result = bind(server_sockfd,(struct
sockaddr*)&server_address,server_len);

        if(FD_ISSET(allConnection[i],&readfds))

 

      if(result!=0)

        {

 

      {

            handleEvent(allConnection[i]);

三.2.叁、等待事件(Waiting for 伊芙nts with Epoll)

           printf(“bind failed\n”);

        }

#include <sys/epoll.h>
int epoll_wait (int epfd,
                struct epoll_event *events,
                int maxevents,
                int timeout);
伺机事件的发生,类似于select()调用。参数events用来从根本获得事件的集合,maxevents告之根本这么些events有多大,这些maxevents的值不能够抢先创立epoll_create()时的size,参数timeout是逾期时间(皮秒,0会立即重临,-一将不分明,也有
说法说是恒久阻塞)。该函数再次回到必要处理的风浪数量,如重回0表示已逾期。
二个简便示例:

           exit(1);                             //在stdlib.h

    }

澳门金沙国际 10代码

      }   

}

澳门金沙国际 11

 

// if(res == 0) handle timeout, res < 0 handle error

#define MAX_EVENTS    64
struct epoll_event *events;
int nr_events, i, epfd;
events = malloc (sizeof (struct epoll_event) * MAX_EVENTS);
if (!events) {
        perror (“malloc”);
        return 1;
}
nr_events = epoll_wait (epfd, events, MAX_EVENTS, -1);
if (nr_events < 0) {
        perror (“epoll_wait”);
        free (events);
        return 1;
}
//只需求检讨发滋事变的文书描述符,而不须要遍历全体描述符
for (i = 0; i < nr_events; i++) {
        printf (“event=%ld on fd=%d\n”,
                events[i].events,
                events[i].data.fd);
        /*
         * We now can, per events[i].events, operate on
         * events[i].data.fd without blocking.
         */
}
free (events);

     

 

澳门金沙国际 12

     

Epoll不仅会告知应用程序有I/0事件来临,还会告知应用程序相关的信息,那一个音信是应用程序填充的,因而根据这一个消息应用程序就能一贯定位到事件,而毋庸遍历整个FD集合。

 

      epfd1 = epoll_create(10000);

intres = epoll_wait(epfd, events, 20, 120);

3.二.四、epoll的优异用法

      ev1.data.fd = server_sockfd;

for(int i = 0; i < res;i++)

澳门金沙国际 13代码

      ev1.events = EPOLLIN;

{

澳门金沙国际 14

      /*

    handleEvent(events[n]);

struct epoll_event ev, *events;
for(;;) {
    nfds = epoll_wait(kdpfd, events, maxevents, -1);
    for(n = 0; n < nfds; ++n) {
        if(events[n].data.fd == listener) {
            //新的接连
            client = accept(listener, (struct sockaddr *) &local,
                            &addrlen);
            if(client < 0){
                perror(“accept”);
                continue;
            }
            setnonblocking(client);
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = client;
        // 设置好event之后,将以此新的event通过epoll_ctl参与到epoll的监听队列之中
            if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) {
                fprintf(stderr, “epoll set insertion error: fd=%d0,
                        client);
                return -1;
            }
        }
        else
            do_use_fd(events[n].data.fd);
    }
}

      printf(“%08x\n”,EPOLLIN);

}

澳门金沙国际 15

      printf(“%08x\n”,EPOLLOUT);

  1. Epoll关键数据结构

 

      printf(“%08x\n”,EPOLLPRI);

前面提到Epoll速度快和其数据结构密不可分,其重点数据结构便是:

叁.3、综合示范

      printf(“%08x\n”,EPOLLERR);

structepoll_event {

澳门金沙国际 16代码

      printf(“%08x\n”,EPOLLHUP);

    __uint32_t events;      // Epoll events

澳门金沙国际 17

      printf(“%08x\n”,EPOLLET);

    epoll_data_t data;      // User datavariable

//echo_epoll_server.c
#include “echo.h”
#include <sys/epoll.h>
#include <fcntl.h>

      printf(“%08x\n”,EPOLLONESHOT);

};

#define EVENT_ARR_SIZE 20
#define EPOLL_SIZE     20

      */

typedef union epoll_data {

void setnonblocking(
    int sockfd
);

      epoll_ctl(epfd1,EPOLL_CTL_ADD,server_sockfd,&ev1);

    void *ptr;

int
main(int argc, char **argv)
{
    int        i,  listenfd, connfd, sockfd, epfd;
    ssize_t        n;
    char            buf[MAXLINE];
    socklen_t        clilen;
    struct sockaddr_in    cliaddr, servaddr;
    struct epoll_event ev, evs[EVENT_ARR_SIZE];
    int   nfds;

     

   int fd;

    if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        err_sys(“create socket error!\n”);
    setnonblocking(listenfd);

     

    __uint32_t u32;

    epfd = epoll_create(EPOLL_SIZE);
    ev.data.fd = listenfd;
    ev.events = EPOLLIN | EPOLLET;
    if(epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev) < 0)
        err_sys(“epoll_ctl listenfd error!\n”);
    
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    //servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_addr.s_addr = inet_addr(“211.67.28.128”);
    servaddr.sin_port        = htons(SERV_PORT);

     

    __uint64_t u64;

    if(bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0)
        err_sys(“bind error!\n”);

      result = listen(server_sockfd,5);

} epoll_data_t;

    if(listen(listenfd, LISTENQ) < 0)
        err_sys(“listen error!\n”);

      if(result!=0)

可见epoll_data是三个union结构体,借助于它应用程序可以保存繁多品种的新闻:fd、指针等等。有了它,应用程序就能够直接固定指标了。

    printf(“server is listening….\n”);

      {

6. 使用Epoll

    for ( ; ; ) {
        if((nfds = epoll_wait(epfd, evs, EVENT_ARR_SIZE, -1)) < 0)
            err_sys(“epoll_wait error!\n”);

           printf(“listen failed\n”);

既然Epoll相比较select这么好,那么用起来何等呢?会不会很麻烦啊…先看看上边包车型客车五个函数吧,就知晓Epoll的易用了。

        for(i = 0; i < nfds; i++)
        {
                if(evs[i].data.fd == listenfd)
                {
                    clilen = sizeof(cliaddr);
                    connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &clilen);
                    if(connfd < 0)
                        continue;
                        
                    setnonblocking(connfd);
                    ev.data.fd = connfd;
                    ev.events = EPOLLIN | EPOLLET;
                    if (epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev) < 0)
                        err_sys(“epoll_ctl connfd error!\n”);            
                }
                else if(evs[i].events & EPOLLIN)
                {
                    sockfd = evs[i].data.fd;
                    if (sockfd < 0)
                        continue;
                    if ( (n = read(sockfd, buf, MAXLINE)) == 0) {
                        epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, &ev);
                        close(sockfd);
                        evs[i].data.fd = -1;
                    } 
                    else if(n < 0)
                        err_sys(“read socket error!\n”);
                    else
                    {
                        printf(“write %d bytes\n”, n);
                        write(sockfd, buf, n);
                    }
                }
                else
                    printf(“other event!\n”);
        }
    }
    return 0;
}

           exit(1);

 

void setnonblocking(
    int sockfd
)
{
    int flag;
    
    flag = fcntl(sockfd, F_GETFL);
    if(flag < 0)
            err_sys(“fcnt(F_GETFL) error!\n”);
    flag |= O_NONBLOCK;
    if(fcntl(sockfd, F_SETFL, flag) < 0)
        err_sys(“fcon(F_SETFL) error!\n”);
}

      }

intepoll_create(int size);

//echo.h
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

     

更动一个Epoll专用的文件描述符,其实是报名四个基本空间,用来存放你想关怀的socket
fd上是或不是发生以及发生了怎样风浪。size正是您在那么些Epoll
fd上能关怀的最大socket fd数,大小自定,只要内部存款和储蓄器丰盛。

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

      memset(buff,0,1024);

intepoll_ctl(int epfd, intop, int fd, structepoll_event *event);

#define SERV_PORT     9877
#define MAXLINE        4096
#define LISTENQ        5

      strncpy(buff,”this is server”,14);

决定有些Epoll文件讲述符上的事件:注册、修改、删除。个中参数epfd是epoll_create()创设Epoll专用的文书讲述符。相对于select模型中的FD_SET和FD_CLR宏。

void
err_sys(const char *fmt, …);

     

intepoll_wait(int epfd,structepoll_event *
events,int maxevents,int timeout);

ssize_t                        
readn(int fd, void *vptr, size_t n);

      for(;;)

等候I/O事件的爆发;参数表明:

澳门金沙国际 18

      {   

epfd:由epoll_create() 生成的Epoll专用的公文讲述符;

           epollreturn  = epoll_wait(epfd1,ev,20,4000);

epoll_event:用于回传代处管事人件的数组;

           printf(“epollreturn is %d\n”,epollreturn);

maxevents:每一回能处理的事件数;

增加补充部分:

           if(epollreturn>0)

timeout:等待I/O事件发生的超时值;

select()系统调用提供1个编写制定来完成协同多元I/O:

           {

回来发滋事变数。

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select (int n,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);

FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);

                 for(i=0;i<epollreturn;i++)

相对于select模型中的select函数。

调用select()将卡住,直到钦定的文本讲述符准备好推行I/O,恐怕可选参数timeout钦定的时刻已经与世长辞。
监视的文本讲述符分为三类set,每一种对应等待不一致的轩然大波。readfds中列出的文件讲述符被监视是还是不是有多少可供读取(假如读取操作达成则不会卡住)。writefds中列出的公文讲述符则被监视是不是写入操作实现而不打断。最终,exceptfds中列出的文书讲述符则被监视是还是不是发生相当,只怕不能够调控的数据是不是可用(这一个景况只有使用于套接字)。那叁类set能够是NULL,那种情景下select()不监视那一类事件。
select()成功再次回到时,每组set都被改换以使它只包涵准备好I/O的文件讲述符。例如,要是有多个文件描述符,值分别是7和9,被放在readfds中。当select()重回时,假设7如故在set中,则那个文件讲述符已经准备好被读取而不会堵塞。假如玖曾经不在set中,则读取它将大概会卡住(小编说只怕是因为数量大概刚刚在select再次来到后就可用,那种意况下,下1次调用select()将回来文件讲述符准备好读取)。
首先个参数n,等于全数set中最大的这几个文件讲述符的值加一。由此,select()的调用者负责检查哪个文件讲述符具备最大值,并且把那一个值加一再传递给第二个参数。
timeout参数是一个指向timeval结构体的指针,timeval定义如下:

                 {

7. 例子程序

#include <sys/time.h>
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* 10E-6 second */
};

                     

上边是一个轻巧Echo
Server的例子程序,麻雀虽小,5脏俱全,还包括了二个简约的晚点检查体制,简洁起见未有做错误处理。

比方那一个参数不是NULL,则正是没有公文讲述符准备好I/O,select()也会在通过tv_sec秒和tv_usec飞秒后重回。当select()再次回到时,timeout参数的气象在差别的系统中是未定义的,因而老是调用select()从前务必再度初阶化timeout和文书讲述符set。实际上,当前版本的Linux会自动修改timeout参数,设置它的值为剩余时间。由此,假诺timeout棉被服装置为5秒,然后在文件讲述符准备好从前经过了3秒,则那贰遍调用select()重返时tv_sec将变为2。
倘诺timeout中的四个值都安装为0,则调用select()将立刻再次来到,报告调用时有所未决的事件,但不等待其余随后的轩然大波。
文件讲述符set不会一向操作,一般接纳多少个帮手宏来管理。那允许Unix系统以相好喜爱的办法来贯彻文件讲述符set。但大诸多类别都简短地贯彻set为位数组。FD_ZERO移除内定set中的全数文件讲述符。每1遍调用select()此前都应该先调用它。
fd_set
writefds;
FD_ZERO(&writefds);
FD_SET增加多个文书讲述符到钦定的set中,FD_CLLX570则从钦定的set中移除贰个文本讲述符:
FD_SET(fd,
&writefds); /* add ‘fd’ to the set */
FD_CLR(fd,
&writefds); /* oops, remove ‘fd’ from the set */
统一筹划优秀的代码应该永世不选拔FD_CL景逸SUV,而且真实处境中它也实在很少被使用。
FD_ISSET测试3个文本讲述符是不是钦点set的1部分。纵然文件讲述符在set中则赶回贰个非0整数,不在则再次来到0。FD_ISSET在调用select()再次回到之后选取,测试内定的公文讲述符是还是不是准备好有关动作:
if
(FD_ISSET(fd, &readfds))
/*
‘fd’ is readable without blocking! */
因为文件讲述符set是静态创立的,它们对文本讲述符的最大数据强加了贰个范围,能够放进set中的最大文件讲述符的值由FD_SETSIZE钦点。在Linux中,那个值是10二4。本章前面大家还将看到那么些界定的衍生物。
再次来到值和错误代码
select()成功时回来准备好I/O的文件讲述符数目,包涵具有八个set。如若提供了timeout,重临值恐怕是0;错误时重返-一,并且安装errno为下边多少个值之1:
EBADF,给某些set提供了没用文件讲述符。
EINTHaval,等待时捕获到复信号,能够重复发起调用。
EINVAL,参数n为负数,大概钦命的timeout非法。

                    
if(ev[i].data.fd==server_sockfd)//假若新监测到三个SOCKET用户连接到了绑定的SOCKET端口,建立新的接连。

[cpp] view
plaincopy

ENOMEM,不够可用内存来成功请求。

poll()系统调用是System V的多元I/O化解方案。它化解了select()的多少个不足,尽管select()依然平时利用(诸多依然由于习惯,或许打着可移植的名义):

#include <sys/poll.h>
int poll (struct pollfd *fds, unsigned int nfds, int timeout);

和select()不同,poll()未有使用低效的多个基于位的文书讲述符set,而是采取了1个独自的组织体pollfd数组,由fds指针指向这一个组。pollfd结构体定义如下:

#include <sys/poll.h>

struct pollfd {
int fd; /* file descriptor */
short events; /* requested events to watch */
short revents; /* returned events witnessed */
};

每三个pollfd结构体钦命了叁个被监视的文本描述符,能够传递几个结构体,提醒poll()监视三个文本讲述符。种种结构体的events域是监视该公文讲述符的轩然大波掩码,由用户来安装这些域。revents域是文件讲述符的操作结果事件掩码。内核在调用再次回到时设置那一个域。events域中呼吁的别样事件都大概在revents域中回到。合法的风云如下:
POLLIN,有数量可读。
POLL奇骏DNOENCOREM,有一般数据可读。
POLLHummerH二DBAND,有优先数据可读。
POLLPKugaI,有急切数据可读。
POLLOUT,写多少不会导致短路。
POLLW途观NO昂科拉M,写普通数据不会产生短路。
POLLWRBAND,写优先数据不会促成短路。
POLLMSG,SIGPOLL信息可用。
其余,revents域中还恐怕回到下列事件:
POLLECRUISER,钦点的文本讲述符发生错误。
POLLHUP,钦赐的文件讲述符挂起风云。
POLLNVAL,钦定的公文讲述符违法。
这一个事件在events域中无意义,因为它们在合适的时候总是会从revents中回到。使用poll()和select()不一致,你不供给显式地请求卓殊景况报告。POLLIN
| POLLP牧马人I等价于select()的读事件,POLLOUT |
POLLWRBAND等价于select()的写事件。POLLIN等价于POLL奇骏DNO库罗德M |
POLLRDBAND,而POLLOUT则等价于POLLWCR-VNO奇骏M。
比如,要同时监视3个文本讲述符是或不是可读和可写,大家得以设置events为POLLIN
|
POLLOUT。在poll重回时,大家能够检查revents中的标记,对应于文件讲述符请求的events结构体。倘若POLLIN事件被设置,则文件讲述符能够被读取而不封堵。就算POLLOUT棉被服装置,则文件讲述符能够写入而不变成短路。这个标记并不是排斥的:它们或许被同时设置,表示这么些文件讲述符的读取和写入操作都会健康重临而不封堵。timeout参数钦点等待的毫秒数,无论I/O是不是准备好,poll都会回到。timeout内定为负数值表示无比超时;timeout为0提示poll调用马上重临并列出准备好I/O的文书描述符,但并不等待别的的风云。那种处境下,poll()就如它的名字这样,一旦大选出来,登时回到。
再次来到值和错误代码
得逞时,poll()再次回到结构体中revents域不为0的文书讲述符个数;即使在逾期前从未有过别的事件发生,poll()重临0;退步时,poll()重返-一,并设置errno为下列值之壹:
EBADF,1个或多少个结构体中钦定的公文讲述符无效。
EFAULT,fds指针指向的地方高出进度的地方空间。
EINT卡宴,请求的事件在此以前爆发一个功率信号,调用能够重复发起。
EINVAL,nfds参数超出PLIMIT_NOFILE值。
ENOMEM,可用内部存款和储蓄器不足,不只怕到位请求。

上述内容出自《OReilly.Linux.System.Programming

  • Talking.Directly.to.the.Kernel.and.C.Library.2007》

Epoll的优点:
一.援助1个历程张开大数据的socket描述符(FD)
    select
最不能够经得住的是一个进度所张开的FD是有必然范围的,由FD_SETSIZE设置,暗中同意值是204捌。对于那多少个须要帮衬的上万总是数目标IM服务器来注脚确太少了。那时候你一是能够选取修改那些宏然后再也编写翻译内核,不过资料也同时提议如此会带动网络作用的下跌,二是足以选拔多进度的缓解方案(古板的
Apache方案),然而即便linux上面成立进度的代价相比小,但如故是不行忽略的,加上进度间数据同步远不如线程间同步的飞跃,所以也不是1种完美的方案。不过epoll则并未有这么些范围,它所支撑的FD上限是最大能够展开文件的多少,这些数字一般远超过204捌,举个例子,在一GB内部存储器的机器上海大学致是拾万左右,具体数目能够cat
/proc/sys/fs/file-max察看,一般的话那一个数量和种类内部存款和储蓄器关系相当的大。

贰.IO效能不随FD数目扩充而线性下跌
   
守旧的select/poll另二个致命缺陷正是当您具备一个不小的socket集合,不过由于互联网延时,任一时间只有部分的socket是”活跃”的,不过select/poll每一遍调用都会线性扫描全体的会合,导致效能彰显线性降低。可是epoll不设有那几个主题材料,它只会对”活跃”的socket进行操作—那是因为在基本完结中epoll是基于各类fd下面的callback函数完成的。那么,唯有”活跃”的socket才会积极性的去调用
callback函数,别的idle状态socket则不会,在这一点上,epoll实现了三个”伪”AIO,因为此时牵重力在os内核。在部分
benchmark中,如若持有的socket基本上都以虎虎有生气的—比如四个高速LAN环境,epoll并不如select/poll有怎么着作用,相反,假诺过多使用epoll_ctl,效用比较还有多少的大跌。但是一旦选取idle
connections模拟WAN环境,epoll的频率就处在select/poll之上了。

3.应用mmap加速内核与用户空间的音讯传递。
   
这一点莫过于涉及到epoll的切实可行落到实处了。无论是select,poll依然epoll都急需内核把FD消息通告给用户空间,如何制止不须要的内部存款和储蓄器拷贝就很重点,在那点上,epoll是经过基础于用户空间mmap同一块内部存款和储蓄器完成的。而一旦你想自个儿同样从二.5内核就关怀epoll的话,一定不会忘记手工业mmap这一步的。

4.内核微调
   
那一点实在不算epoll的独到之处了,而是整个linux平台的亮点。只怕你能够猜疑linux平台,不过你不能够躲避linux平台赋予你微调内核的力量。比如,内核TCP/IP协议栈使用内部存款和储蓄器池管理sk_buff结构,那么能够在运行时代动态调控这些内部存款和储蓄器pool(skb_head_pool)的大小—
通过echo
XXXX>/proc/sys/net/core/hot_list_length落成。再比如listen函数的第3个参数(TCP完结三遍握手的数码包队列长度),也得以依据你平台内部存款和储蓄器大小动态调节。更甚至在多个数量包面数目巨大但同时种种数据包本人尺寸却非常的小的杰出系统上尝试最新的NAPI网卡驱动架构。

########################################################

                      {

  1. //     
  2. // a simple echo server using epoll in linux    
  3. //     
  4. // 2009-11-05    
  5. // 二〇一二-0叁-22:修改了多少个难题,一是/n格式难题,二是去掉了原代码不小心加上的ET格局;  
  6. // 本来只是简短的表示程序,决定还是增进 recv/send时的buffer偏移  
  7. // by sparkling    
  8. //     
  9. #include <sys/socket.h>    
  10. #include <sys/epoll.h>    
  11. #include <netinet/in.h>    
  12. #include <arpa/inet.h>    
  13. #include <fcntl.h>    
  14. #include <unistd.h>    
  15. #include <stdio.h>    
  16. #include <errno.h>    
  17. #include <iostream>    
  18. using namespace std;    
  19. #define MAX_EVENTS 500    
  20. struct myevent_s    
  21. {    
  22.     int fd;    
  23.     void (*call_back)(int fd, int events, void *arg);    
  24.     int events;    
  25.     void *arg;    
  26.     int status; // 1: in epoll wait list, 0 not in    
  27.     char buff[128]; // recv data buffer    
  28.     int len, s_offset;    
  29.     long last_active; // last active time    
  30. };    
  31. // set event    
  32. void EventSet(myevent_s *ev, int fd, void (*call_back)(int, int, void*), void *arg)    
  33. {    
  34.     ev->fd = fd;    
  35.     ev->call_back = call_back;    
  36.     ev->events = 0;    
  37.     ev->arg = arg;    
  38.     ev->status = 0;  
  39.     bzero(ev->buff, sizeof(ev->buff));  
  40.     ev->s_offset = 0;    
  41.     ev->len = 0;  
  42.     ev->last_active = time(NULL);    
  43. }    
  44. // add/mod an event to epoll    
  45. void EventAdd(int epollFd, int events, myevent_s *ev)    
  46. {    
  47.     struct epoll_event epv = {0, {0}};    
  48.     int op;    
  49.     epv.data.ptr = ev;    
  50.     epv.events = ev->events = events;    
  51.     if(ev->status == 1){    
  52.         op = EPOLL_CTL_MOD;    
  53.     }    
  54.     else{    
  55.         op = EPOLL_CTL_ADD;    
  56.         ev->status = 1;    
  57.     }    
  58.     if(epoll_ctl(epollFd, op, ev->fd, &epv) < 0)    
  59.         printf(“Event Add failed[fd=%d], evnets[%d]\n”, ev->fd, events);    
  60.     else    
  61.         printf(“Event Add OK[fd=%d], op=%d, evnets[%0X]\n”, ev->fd, op, events);    
  62. }    
  63. // delete an event from epoll    
  64. void EventDel(int epollFd, myevent_s *ev)    
  65. {    
  66.     struct epoll_event epv = {0, {0}};    
  67.     if(ev->status != 1) return;    
  68.     epv.data.ptr = ev;    
  69.     ev->status = 0;  
  70.     epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &epv);    
  71. }    
  72. int g_epollFd;    
  73. myevent_s g_Events[MAX_EVENTS+1]; // g_Events[MAX_EVENTS] is used by listen fd    
  74. void RecvData(int fd, int events, void *arg);    
  75. void SendData(int fd, int events, void *arg);    
  76. // accept new connections from clients    
  77. void AcceptConn(int fd, int events, void *arg)    
  78. {    
  79.     struct sockaddr_in sin;    
  80.     socklen_t len = sizeof(struct sockaddr_in);    
  81.     int nfd, i;    
  82.     // accept    
  83.     if((nfd = accept(fd, (struct sockaddr*)&sin, &len)) == -1)    
  84.     {    
  85.         if(errno != EAGAIN && errno != EINTR)    
  86.         {    
  87.         }  
  88.         printf(“%s: accept, %d”, __func__, errno);    
  89.         return;    
  90.     }    
  91.     do    
  92.     {    
  93.         for(i = 0; i < MAX_EVENTS; i++)    
  94.         {    
  95.             if(g_Events[i].status == 0)    
  96.             {    
  97.                 break;    
  98.             }    
  99.         }    
  100.         if(i == MAX_EVENTS)    
  101.         {    
  102.             printf(“%s:max connection limit[%d].”, __func__, MAX_EVENTS);    
  103.             break;    
  104.         }    
  105.         // set nonblocking  
  106.         int iret = 0;  
  107.         if((iret = fcntl(nfd, F_SETFL, O_NONBLOCK)) < 0)  
  108.         {  
  109.             printf(“%s: fcntl nonblocking failed:%d”, __func__, iret);  
  110.             break;  
  111.         }  
  112.         // add a read event for receive data    
  113.         EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);    
  114.         EventAdd(g_epollFd, EPOLLIN, &g_Events[i]);    
  115.     }while(0);    
  116.     printf(“new conn[%s:%d][time:%d], pos[%d]\n”, inet_ntoa(sin.sin_addr),   
  117.             ntohs(sin.sin_port), g_Events[i].last_active, i);    
  118. }    
  119. // receive data    
  120. void RecvData(int fd, int events, void *arg)    
  121. {    
  122.     struct myevent_s *ev = (struct myevent_s*)arg;    
  123.     int len;    
  124.     // receive data  
  125.     len = recv(fd, ev->buff+ev->len, sizeof(ev->buff)-1-ev->len, 0);      
  126.     EventDel(g_epollFd, ev);  
  127.     if(len > 0)  
  128.     {  
  129.         ev->len += len;  
  130.         ev->buff[len] = ‘\0’;    
  131.         printf(“C[%d]:%s\n”, fd, ev->buff);    
  132.         // change to send event    
  133.         EventSet(ev, fd, SendData, ev);    
  134.         EventAdd(g_epollFd, EPOLLOUT, ev);    
  135.     }    
  136.     else if(len == 0)    
  137.     {    
  138.         close(ev->fd);    
  139.         printf(“[fd=%d] pos[%d], closed gracefully.\n”, fd, ev-g_Events);    
  140.     }    
  141.     else    
  142.     {    
  143.         close(ev->fd);    
  144.         printf(“recv[fd=%d] error[%d]:%s\n”, fd, errno, strerror(errno));    
  145.     }    
  146. }    
  147. // send data    
  148. void SendData(int fd, int events, void *arg)    
  149. {    
  150.     struct myevent_s *ev = (struct myevent_s*)arg;    
  151.     int len;    
  152.     // send data    
  153.     len = send(fd, ev->buff + ev->s_offset, ev->len – ev->s_offset, 0);  
  154.     if(len > 0)    
  155.     {  
  156.         printf(“send[fd=%d], [%d<->%d]%s\n”, fd, len, ev->len, ev->buff);  
  157.         ev->s_offset += len;  
  158.         if(ev->s_offset == ev->len)  
  159.         {  
  160.             // change to receive event  
  161.             EventDel(g_epollFd, ev);    
  162.             EventSet(ev, fd, RecvData, ev);    
  163.             EventAdd(g_epollFd, EPOLLIN, ev);    
  164.         }  
  165.     }    
  166.     else    
  167.     {    
  168.         close(ev->fd);    
  169.         EventDel(g_epollFd, ev);    
  170.         printf(“send[fd=%d] error[%d]\n”, fd, errno);    
  171.     }    
  172. }    
  173. void InitListenSocket(int epollFd, short port)    
  174. {    
  175.     int listenFd = socket(AF_INET, SOCK_STREAM, 0);    
  176.     fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking    
  177.     printf(“server listen fd=%d\n”, listenFd);    
  178.     EventSet(&g_Events[MAX_EVENTS], listenFd, AcceptConn, &g_Events[MAX_EVENTS]);    
  179.     // add listen socket    
  180.     EventAdd(epollFd, EPOLLIN, &g_Events[MAX_EVENTS]);    
  181.     // bind & listen    
  182.     sockaddr_in sin;    
  183.     bzero(&sin, sizeof(sin));    
  184.     sin.sin_family = AF_INET;    
  185.     sin.sin_addr.s_addr = INADDR_ANY;    
  186.     sin.sin_port = htons(port);    
  187.     bind(listenFd, (const sockaddr*)&sin, sizeof(sin));    
  188.     listen(listenFd, 5);    
  189. }    
  190. int main(int argc, char **argv)    
  191. {    
  192.     unsigned short port = 12345; // default port    
  193.     if(argc == 2){    
  194.         port = atoi(argv[1]);    
  195.     }    
  196.     // create epoll    
  197.     g_epollFd = epoll_create(MAX_EVENTS);    
  198.     if(g_epollFd <= 0) printf(“create epoll failed.%d\n”, g_epollFd);    
  199.     // create & bind listen socket, and add to epoll, set non-blocking    
  200.     InitListenSocket(g_epollFd, port);    
  201.     // event loop    
  202.     struct epoll_event events[MAX_EVENTS];    
  203.     printf(“server running:port[%d]\n”, port);    
  204.     int checkPos = 0;    
  205.     while(1){    
  206.         // a simple timeout check here, every time 100, better to use a mini-heap, and add timer event    
  207.         long now = time(NULL);    
  208.         for(int i = 0; i < 100; i++, checkPos++) // doesn’t check listen fd    
  209.         {    
  210.             if(checkPos == MAX_EVENTS) checkPos = 0; // recycle    
  211.             if(g_Events[checkPos].status != 1) continue;    
  212.             long duration = now – g_Events[checkPos].last_active;    
  213.             if(duration >= 60) // 60s timeout    
  214.             {    
  215.                 close(g_Events[checkPos].fd);    
  216.                 printf(“[fd=%d] timeout[%d–%d].\n”, g_Events[checkPos].fd, g_Events[checkPos].last_active, now);    
  217.                 EventDel(g_epollFd, &g_Events[checkPos]);    
  218.             }    
  219.         }    
  220.         // wait for events to happen    
  221.         int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, 1000);    
  222.         if(fds < 0){    
  223.             printf(“epoll_wait error, exit\n”);    
  224.             break;    
  225.         }    
  226.         for(int i = 0; i < fds; i++){    
  227.             myevent_s *ev = (struct myevent_s*)events[i].data.ptr;    
  228.             if((events[i].events&EPOLLIN)&&(ev->events&EPOLLIN)) // read event    
  229.             {    
  230.                 ev->call_back(ev->fd, events[i].events, ev->arg);    
  231.             }    
  232.             if((events[i].events&EPOLLOUT)&&(ev->events&EPOLLOUT)) // write event    
  233.             {    
  234.                 ev->call_back(ev->fd, events[i].events, ev->arg);    
  235.             }    
  236.         }    
  237.     }    
  238.     // free resource    
  239.     return 0;    
  240. }     

select/epoll的特点

select的性状:select
选取句柄的时候,是遍历所有句柄,约等于说句柄有事件响应时,select必要遍历全数句柄技巧获得到怎么着句柄有事件通报,因而作用是相当的低。但是只要总是很少的气象下,
select和epoll的LT触发形式相比较, 品质上差异十分小。
那 里要多说一句,select辅助的句柄数是有限定的,
同时只协助10二伍个,这几个是句柄集合限制的,假设越过这几个界定,很或者造成溢出,而且这一个不易于察觉难点,
TAF就涌出过这些难题,
调节和测试了n天,才意识:)当然能够通过修改linux的socket内核调节那些参数。
epoll的表征:epoll对于句柄事件的选拔不是遍历的,是事件响应的,正是句柄上事件来就立马挑选出来,不须求遍历整个句柄链表,因而效能相当高,内核将句柄用红黑树保存的。相比较于select,epoll最大的裨益在于它不会趁机监听fd数指标增加而降落作用。因为在基础中的select完成中,它是行使轮询来拍卖的,轮询的fd数目越来越多,自然耗费时间更加多。并且,在linux/posix_types.h头文件有那样的宣示:
#define __FD_SETSIZE    1024
表示select最多而且监听拾2多少个fd,当然,能够由此改造头文件再重编写翻译内核来扩充这几个数量,但那仿佛并不治本。

对于epoll来讲还有ET和LT的区别,LT表示水平触发,ET表示边缘触发,两者在品质以及代码实现上距离也是非常大的。

                           

epoll的LT和ET的区别

LT:水平触发,功用会低于ET触发,特别在大并发,大流量的气象下。不过LT对代码编写供给相比低,不易于并发难题。LT情势服务编写上的突显是:只要有数据未有被获取,内核就持续公告你,因而不用操心事件不见的景况。
ET:边缘触发,效能越发高,在产出,大流量的动静下,会比LT少许多epoll的系统调用,因而功效高。可是对编制程序须要高,必要细致的处理各种请求,否则轻便产生丢失事件的情事。

                            client_sockfd =
accept(server_sockfd,(struct sockaddr *)&client_address,
&client_len);//没有总结client_len的值,会导致accept返回-1

epoll相关API

epoll的接口极度轻巧,壹共就四个函数:

                            printf(“accept one
client,socket:%d\n”,client_sockfd);                        

1. int epoll_create(int size);

创立二个epoll的句柄,size用来报告内核这一个监听的数额1共有多大。这么些参数差异于select()中的第贰个参数,给出最大监听的fd+一的值。须求注意的是,当创制好epoll句柄后,它正是会攻克3个fd值,在linux下假使翻开/proc/进程id/fd/,是力所能及见到这一个fd的,所以在运用完epoll后,必须调用close()关闭,不然大概形成fd被耗尽。

                            ev1.data.fd=client_sockfd;

2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epoll的事件注册函数,它分裂与select()是在监听事件时告诉内核要监听什么类型的风云,而是在此处先挂号要监听的轩然大波类型。第二个参数是epoll_create()的返回值,首个参数表示动作,用四个宏来表示:
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD:修改已经登记的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删去一个fd;
其多个参数是亟需监听的fd,第四个参数是报告内核要求监听什么事,struct
epoll_event结构如下:

typedef
union epoll_data {
   
void *ptr;
   
int fd;
   
__uint32_t u32;
   
__uint64_t u64;
}
epoll_data_t;

struct
epoll_event {
   
__uint32_t events; /* Epoll events */
   
epoll_data_t data; /* User data variable */
};

events能够是以下多少个宏的成团:
EPOLLIN
:表示对应的公文讲述符能够读(包含对端SOCKET经常关闭);
EPOLLOUT:表示对应的文本讲述符能够写;
EPOLLPSportageI:表示对应的文本讲述符有殷切的数目可读(那里应该代表有带外数据来临);
EPOLLEMurano路虎极光:表示对应的公文讲述符爆发错误;
EPOLLHUP:表示对应的文本讲述符被挂断;
EPOLLET:
将EPOLL设为边缘触发(艾德ge Triggered)格局,这是相对于水平触发(Level
Triggered)来说的。
EPOLLONESHOT:只监听二遍事件,当监听完本次风云过后,假若还亟需继续监听这些socket的话,必要再度把这几个socket参预到EPOLL队列里

                            ev1.events=EPOLLIN;

3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

伺机事件的发出,类似于select()调用。参数events用来从根本得到事件的聚合,maxevents告之根本那么些events有多大,那一个maxevents的值不能够抢先制造epoll_create()时的size,参数timeout是晚点时间(阿秒,0会立时再次回到,-一将不明确,也有说法正是永世阻塞)。该函数再次来到须要处理的轩然大波数量,如再次回到0表示已逾期。

                           
epoll_ctl(epfd1,EPOLL_CTL_ADD,client_sockfd,&ev1);

示范代码

                           

epoll服务器

  1. #include <sys/epoll.h>  
  2. #include <netinet/in.h>  
  3. #include <sys/types.h>          /* See NOTES */  
  4. #include <sys/socket.h>  
  5. #include <string.h>  
  6. #include <stdio.h>  
  7. #include <unistd.h>  
  8. #include <fcntl.h>  
  9.   
  10. #include <errno.h>  
  11. #include <stdlib.h>  
  12. typedef struct sockaddr_in sockaddr_in ;  
  13. typedef struct sockaddr     sockaddr ;  
  14.   
  15. #define SER_PORT    8080  
  16.   
  17. int nonblock(int fd){  
  18.     int opt ;  
  19.     opt = fcntl(fd,F_GETFL);  
  20.     opt |= O_NONBLOCK ;  
  21.     return fcntl(fd,F_SETFL,opt);  
  22. }  
  23.   
  24. int main(int argc,char**argv){  
  25.     sockaddr_in srv, cli ;  
  26.     int listen_fd ,con_fd ;  
  27.     socklen_t  len;  
  28.     int res ,nsize,ws;  
  29.     char buf[255];  
  30.   
  31.     int epfd,ers;  
  32.     struct epoll_event evn,events[50];  
  33.     int i;  
  34.   
  35.     bzero(&srv,sizeof(srv));  
  36.     bzero(&cli,sizeof(cli));  
  37.     srv.sin_port= SER_PORT ;  
  38.     srv.sin_family = AF_INET ;  
  39.     listen_fd = socket(AF_INET,SOCK_STREAM,0);  
  40.   
  41.     int yes = 1;  
  42.     setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int));  
  43.   
  44.     if(bind(listen_fd,(sockaddr*)&srv,sizeof(sockaddr))<0)  {  
  45.         perror(“bind”);  
  46.         exit(0);  
  47.     }  
  48.     listen(listen_fd,100);  
  49.     nonblock(listen_fd);  
  50.     epfd = epoll_create(200);  
  51.     evn.events = EPOLLIN|EPOLLET ;  
  52.     evn.data.fd = listen_fd;   
  53.     epoll_ctl(epfd,EPOLL_CTL_ADD,listen_fd,&evn);  
  54.     static int count ;  
  55.     while(1){  
  56.         ers = epoll_wait(epfd,events,100,5000);  
  57.         if(ers<0 ){  
  58.             perror(“epoll_wait:”);exit(0);  
  59.         }else if(ers==0){  
  60.             printf(“time out:%d\n”,count++);  
  61.             continue ;  
  62.         }  
  63.         for(i=0;i<ers;i++){  
  64.             if(events[i].data.fd == listen_fd){  
  65.                 con_fd = accept(listen_fd,(sockaddr*)&cli ,&len);  
  66.                 nonblock(con_fd);  
  67.                 printf(“connect from:%s\n”,inet_ntoa(cli.sin_addr));  
  68.                 evn.data.fd = con_fd;  
  69.                 evn.events = EPOLLIN | EPOLLET ;  
  70.                 epoll_ctl(epfd,EPOLL_CTL_ADD,con_fd,&evn);  
  71.   
  72.             }else if(events[i].events & EPOLLIN){     
  73.                   
  74.                 nsize = 0;  
  75.                 while((res=read(events[i].data.fd,buf+nsize,sizeof(buf)-1))>0){  
  76.                     nsize+= res;  
  77.                 }  
  78.                 if(res==0){  
  79.                     epoll_ctl(epfd,EPOLL_CTL_DEL,events[i].data.fd,NULL);     
  80.                     printf(“a client over\n”);  
  81.                     close(con_fd);  
  82.                     continue ;  
  83.                 }else if(res<0 && errno!=EAGAIN){  
  84.                     perror(“read”);  
  85.                     continue ;  
  86.                 }  
  87.                 buf[nsize]=0;  
  88.                 evn.data.fd = events[i].data.fd;  
  89.                 evn.events=EPOLLOUT|EPOLLET ;  
  90.                 epoll_ctl(epfd,EPOLL_CTL_MOD,events[i].data.fd,&evn);                 
  91.                   
  92.             }else if(events[i].events & EPOLLOUT){  
  93.                 nsize = strlen(buf);  
  94.                 ws = 0;  
  95.                 while(nsize>0){  
  96.                      ws=write(events[i].data.fd,buf,nsize);  
  97.                     nsize-=ws;  
  98.                 }  
  99.                 evn.data.fd = events[i].data.fd;  
  100.                 evn.events=EPOLLIN|EPOLLET ;  
  101.                 epoll_ctl(epfd,EPOLL_CTL_MOD,events[i].data.fd,&evn);     
  102.             }else{  
  103.                 printf(“others\n”);  
  104.                   
  105.             }             
  106.         }  
  107.   
  108.     }  
  109.   
  110.     close(listen_fd);  
  111.       
  112.     return 0;  
  113. }  

澳门金沙国际 19

                            //ev1.data.fd=client_sockfd;

客户端测试代码:

  1. #include <sys/epoll.h>  
  2. #include <netinet/in.h>  
  3. #include <sys/types.h>          /* See NOTES */  
  4. #include <sys/socket.h>  
  5. #include <strings.h>  
  6. #include <stdio.h>  
  7. #include <stdlib.h>  
  8. #include <unistd.h>  
  9. typedef struct sockaddr_in sockaddr_in ;  
  10. typedef struct sockaddr     sockaddr ;  
  11.   
  12. #define SER_PORT    8080  
  13. #define IP_ADDR     “10.33.28.230”  
  14.   
  15. int main(int argc,char**argv){  
  16.     sockaddr_in srv, cli ;  
  17.     int listen_fd ,con_fd ;  
  18.     socklen_t  len;  
  19.     int res,ws ;  
  20.     char buf[255];  
  21.   
  22.     bzero(&srv,sizeof(srv));  
  23.     bzero(&cli,sizeof(cli));  
  24.     srv.sin_port= SER_PORT ;  
  25.     srv.sin_family = AF_INET ;  
  26.     inet_pton(AF_INET,IP_ADDR,&srv.sin_addr);  
  27.   
  28.     listen_fd = socket(AF_INET,SOCK_STREAM,0);  
  29.     if(connect(listen_fd,(sockaddr*)&srv,sizeof(sockaddr))<0){  
  30.         perror(“connect”);  
  31.         exit(0);  
  32.     }  
  33.     while(1){  
  34.         res = read(STDIN_FILENO,buf,sizeof(buf)-1);  
  35.         ws = write(listen_fd,buf,res);  
  36.         res = read(listen_fd,buf,sizeof(buf)-1);  
  37.         ws = write(STDOUT_FILENO,buf,res);  
  38.     }  
  39.   
  40.     close(listen_fd);  
  41.       
  42.     return 0;  
  43. }  

                            //ev1.events=EPOLLOUT;

                           
//epoll_ctl(epfd1,EPOLL_CTL_ADD,client_sockfd,&ev1); //注册

                      }

                      else
if(ev[i].events&EPOLLIN)//假设是一度延续的用户,收到多少,那么举办读入。

                      {

                            sockfd = ev[i].data.fd;

                            if (sockfd < 0)

                            {

                                  printf(“EPOLLIN,sockfd < 0\n”);

                                  continue;

                            }

                            res = recv(sockfd,&ch,1,0);

                                                       

                            if (res < 0)

                            {

                                 if (errno == ECONNRESET)

                                  {

                                       close(sockfd);

                                       ev[i].data.fd = -1;

                                       printf(“EPOLLIN,res<0,errno ==
ECONNRESET\n”);

                                  }

                                  else

                                  printf(“EPOLLIN,recv error,res
<0\n”);

                            }

                            else if (res == 0)

                            {

                                  close(sockfd);                   
//个测试发现关闭socket,epoll队列中就不再监视这么些socket了,如同不需求删除监视

                                  ev[i].data.fd = -1;

                                  printf(“EPOLLIN,res == 0\n”);

                                  ev1.data.fd=sockfd;

                                  ev1.events=EPOLLIN;

                                 
epoll_ctl(epfd1,EPOLL_CTL_DEL,sockfd,&ev1);

                            }

                            else

                            {

                                  printf(“EPOLLIN,receive one char
%c,socket is %d\n”,ch,sockfd);

                            }

 

                            ev1.data.fd=sockfd; 

                            ev1.events=EPOLLOUT;

                           
epoll_ctl(epfd1,EPOLL_CTL_MOD,sockfd,&ev1);

                            /**/

                      }

                     

                      else if(ev[i].events&EPOLLOUT) //
监测数据发送的规律是,对端调用recv,布告到劳动器端,通告epoll,那么些socket有多少要发。

                      {

                            sockfd = ev[i].data.fd;

                            res = send(sockfd,buff,102,0);

                            if(res==-1)

                            {

                                  printf(“send error,res is %d\n”,res);

                                  close(sockfd);

                                  ev1.data.fd=sockfd;

                                  ev1.events=EPOLLOUT;

                                 
epoll_ctl(epfd1,EPOLL_CTL_DEL,sockfd,&ev1);

                            }

                           

                           

                            ev一.data.fd=sockfd;
//设置用于读操作的文件讲述符

                            ev1.events=EPOLLIN;
//设置用于注测的读操作事件

                           
epoll_ctl(epfd1,EPOLL_CTL_MOD,sockfd,&ev1); 
//修改sockfd上要拍卖的风浪为EPOLIN

                           

                      }

                

                

                 }

          

          

           }

          

     

     

      }

      return 0;

}

 

 

client2.c

#include <sys/types.h>

#include <sys/socket.h>

#include <stdio.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>                     //包含memset strncpy

 

int main(int argc,char* argv[])                         //

{                                                       //

      int sockfd;                                         // 

      int len,i,res;

      struct sockaddr_in address;

      int result;

      char ch = ‘A’;

      char buff[1024];

     

      sockfd = socket(AF_INET,SOCK_STREAM,0);             
//古怪,叁个client运营三个本子,每一次得到的竟然是同七个socket。改个名字也13分

      printf(“socket is %d\n”,sockfd);

      address.sin_family = AF_INET;

      address.sin_addr.s_addr = inet_addr(“192.168.131.129”);

      address.sin_port = htons(9734);

      len = sizeof(address);

     

      result = connect(sockfd,(struct sockaddr*)&address,len);

      if(result == -1)

      {

           perror(“oops:client1”);

           exit(-1);

      }

     

      memset(buff,0,1024);

      i = 0;

      //for(i=0;i<10;i++)

      for(;;)

      {  

           res = send(sockfd,&ch,1,0);

           if(res==-1)

           {

                 printf(“send error,res is %d,exiting program\n”,res);

                 close(sockfd);

                 return(-1);

           }

           /**/ 

           i++;

            memset(buff,0,102);

           res = recv(sockfd,buff,102,0); 

          

            //if((res==-1)||(res==0))

           if(res==-1)                       

           {

                 printf(“recv error,res is %d,exiting program\n”,res);

                 close(sockfd);

                 return(-1);

           }

           printf(“socket:%d,buff is %s,i is %d\n”,sockfd,buff,i);

           /**/

      }

      //scanf(“%s”,buff);

      printf(“exiting program\n”);

      close(sockfd);  

      return 0;

}

 

相关文章