epoll整理计算,c语言多进度tcp服务器示例

By admin in 美高梅手机版4858 on 2019年4月14日

互联网上有所素材都说epoll是高并发、单线程、IO重叠服用的首选框架结构,比select和poll质量都要好,特别是在有大气不活跃接连的情景下。具体原理就不演说了,上边说说采纳。

server.h

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

原地址:

具备有七个函数:

复制代码 代码如下:

NAME
       epoll – I/O event notification facility

第3对小编表示谢谢,整理的很详细,读完收益匪浅!!!

#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 在 Linux二.陆内核中标准引进,和 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;

其实,壹切的分解都是多余的,依据小编日前的摸底,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)//假使新监测到贰个HTTP用户连接到绑定的HTTP端口,建立新的连年。由于我们新利用了SOCKET连接,所以基本没用。
    {
     OnAcceptHttpEpoll ();
    }
    else if (m_events[i].data.fd ==
m_listen_sock_fd)//假诺新监测到二个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;
  On提姆er ();//进行局地定时的操作,首要就是去除一些短线用户等。
 }

这三种模型思想周边,正是让每四个赶到的连接一边协调干活儿去,别再来烦小编 。只是
PPC 是为它开了二个进度,而 TPC
开了一个线程。但是别烦作者是有代价的,它要时间和空中啊,连接多了今后,那么多的经过
/
线程切换,那费用就上去了;由此那类模型能经受的最罗安达接数都不会高,一般在几百个左右。

(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,想做三个高并发的代办程序。刚伊始真是郁闷,一向搞不通,网上也有几篇介绍epoll的稿子。但都不深切,未有将1部分专注的地点注脚。以至于走了成百上千弯路,现将团结的片段了然共享给大家,以少走弯路。 

  1. 最大并发数限制,因为2个进度所打开的 FD (文件讲述符)是有限定的,由
    FD_SETSIZE 设置,暗中同意值是 十24/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”);

一epoll回到时已经明确的接头哪些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)
该函数生成3个epoll专用的文本讲述符。它事实上是在基础申请壹上空,用来存放你想关心的socket
fd上是还是不是暴发以及发生了何等风浪。size便是您在这几个epoll
fd上能爱护的最大socket
fd数。随你定好了。只要您有空间。可参见上面与select之分裂2. 

大多功用和 select 是1模1样的, select 缺点的 二 和 3 它都没有改掉。

(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
未有最大产出连接的界定,上限是最大能够打开文件的数额,这几个数字1般远大于
204八, 相似的话这一个数量和系统内部存储器关系非常的大 ,具体数额可以 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 。

     __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:表示对应的公文讲述符能够写;
EPOLLP安德拉I:表示对应的文本讲述符有热切的数据可读
EPOLLEGL450RAV4:表示对应的文件讲述符爆发错误;
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
的急迅和其数据结构的设计是壹环扣1环的,这几个下边就会涉及。

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

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

 

第2回顾一下 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

 EPOLLPCR-VI:表示对应的文书讲述符有紧迫的多寡可读(那里应该代表有带外数据来临);
EPOLLE奇骏陆风X8:表示对应的文书讲述符产生错误;

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:只监听3次事件,当监听完本次风云之后,如若还必要持续监听这几个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 是2个 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: 任何人能够Infiniti制复制代码并选用那一个文书档案,当然包罗你的经贸用途 
  39. * 但请遵照GPL 
  40. *Thanks to:Google 
  41. *霍普:希望进一步多的人贡献自个儿的力量,为科学和技术进步效力 
  42. * 科学和技术站在巨人的肩膀上进步更加快!多谢有开源前辈的贡献! 
  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 专用的文书描述符,其实是申请一个根本空间,用来存放在你想关心的
socket fd 上是不是发生以及产生了怎么样风云。 size 正是你在这几个 Epoll fd
上能关注的最大 socket fd 数,大小自定,只要内部存储器丰盛。

epoll_wait的行事流程是:等待,若是有epoll事件产生立即回去,不然等待timeout皮秒。再次来到时拷贝要处理的轩然大波到events指向的数组,再次回到就绪的文本讲述符的个数,失败时重回-1并设置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为-1是,epoll_wait调用将永久阻塞,直到有个别事件时有产生。当timeout为0时,epoll_wait调用将即时回到。 

[java] view
plaincopy

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

maxevents:钦赐最多监听多少个事件。若是events指向的是1几个单元的布局体数组,那么就设置maxevents为20。 

 

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

events:
events指向的数组元帅拷贝全体就绪的轩然大波,从水源事件表中。events的成员是struct
epoll_event类型,1般蕴涵events(其值是如:EPOLLIN、EPOLLOUT等)。还有3个是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. epoll整理计算,c语言多进度tcp服务器示例。    return 0;  
  84. }  

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

epoll.c

 epoll_wait运维的原理是 等侍注册在epfd上的socket
fd的轩然大波的产生,假诺爆发则将生出的sokct fd和事件类型放入到events数组中。
并且将登记在epfd上的socket
fd的轩然大波类型给清空,所以要是下四个循环你还要关切这几个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>

2、第③个示范:

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

#include <sys/socket.h>

 

7). 例子程序

#include <stdlib.h>

  1. Epoll是何方神圣?

上边是一个简单 Echo Server
的事例程序,麻雀虽小,伍脏俱全,还带有了一个简约的晚点检查体制,简洁起见未有做错误处理。

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

Epoll可是脚下在Linux下支付大规模出现互连网程序的走俏人选,Epoll 在Linux2.陆内核中正式引进,和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;

 

假定不摆出来别的模型的瑕疵,怎么能对照出Epoll的优点呢。

3、epoll
3.1、poll(select)的限制
     
Poll函数源点于SVKuga3,最初局限于流设备,SV猎豹CS6肆打消了那种范围。总是来说,poll比select要火速1些,不过,它有可移植性难点,例如,windows就只接济select。
2个poll的简便例子:

 

2.1 PPC/TPC模型

美高梅手机版4858 1代码

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

那三种模型思想周围,正是让每一个赶到的连年1边自身办事去,别再来烦小编。只是PPC是为它开了二个经过,而TPC开了二个线程。可是别烦小编是有代价的,它要时刻和空中啊,连接多了今后,那么多的进度/线程切换,那开支就上去了;因而那类模型能承受的最卢萨卡接数都不会高,1般在几百个左右。

美高梅手机版4858 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设置,私下认可值是1024/2048,由此Select模型的最大并发数就被相应限制了。本身改改这几个FD_SETSIZE?想法虽好,可是先看看上面吧…

美高梅手机版4858 3

      int epfd1;int result;

二. 效能难点,select每趟调用都会线性扫描全体的FD集合,那样功效就会显现线性下跌,把FD_SETSIZE改大的结局正是,大家都逐渐来,什么?都超时了??!!

 

      int server_len,client_len;

三. 根本/用户空间 内部存款和储蓄器拷贝难点,如何让内核把FD音讯布告给用户空间啊?在这几个题材上select接纳了内部存款和储蓄器拷贝方法。

    
select模型与此类例。内核必须遍历全体监视的描述符,而应用程序也务必遍历全体描述符,检查哪些描述符已经准备好。当描述符成百上千时,会变得杰出低效——那是select(poll)模型低效的起点所在。思念那么些情况,二.6之后的基本都推荐了epoll模型。

      int server_sockfd,client_sockfd;

2.3 poll模型

三.2、宗旨数据结构与接口
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是同一的,select缺点的2和三它都未曾改掉。

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的优点了。

美高梅手机版4858 4代码

      struct epoll_event ev[20];

三.一.
Epoll从未有过最大出现连接的限制,上限是最大能够打开文件的数量,那些数字一般远不止204八, 1般的话那个数据和种类内部存款和储蓄器关系非常大,具体多少能够cat
/proc/sys/fs/file-max察看。

美高梅手机版4858 5

      int epollreturn;

三.贰. 效用升高,Epoll最大的亮点就在于它只管你“活跃”的连接,而跟连接总数无关,因而在实质上的互联网环境中,Epoll的频率就会远远出乎select和poll。

#include <sys/epoll.h>
int epoll_美高梅手机版4858 ,ctl (int epfd,
               int op,
               int fd,
               struct epoll_event *event);

      int i,j,res;

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

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

      int sockfd;

 

美高梅手机版4858 6

      char ch = ‘0’;

 

 

      char buff[1024];

  1. Epoll为啥高效

 

     

Epoll的神速和其数据结构的宏图是密不可分的,那个上边就会涉嫌。

 

      server_address.sin_family = AF_INET;

第三遍顾一下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)

美高梅手机版4858 7代码

      server_len = sizeof(server_address);

{

美高梅手机版4858 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”);

     

    {

美高梅手机版4858 9

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

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

 

      if(result!=0)

        {

 

      {

            handleEvent(allConnection[i]);

3.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表示已逾期。
2个简单示例:

           exit(1);                             //在stdlib.h

    }

美高梅手机版4858 10代码

      }   

}

美高梅手机版4858 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);

     

 

美高梅手机版4858 12

     

Epoll不仅会报告应用程序有I/0事件来临,还会报告应用程序相关的消息,那一个音信是应用程序填充的,因而依照那个新闻应用程序就能直接定位到事件,而不要遍历整个FD集合。

 

      epfd1 = epoll_create(10000);

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

三.贰.四、epoll的第一名用法

      ev1.data.fd = server_sockfd;

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

美高梅手机版4858 13代码

      ev1.events = EPOLLIN;

{

美高梅手机版4858 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);

}

美高梅手机版4858 15

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

  1. Epoll关键数据结构

 

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

眼下提到Epoll速度快和其数据结构密不可分,其首要数据结构就是:

三.叁、综合示范

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

structepoll_event {

美高梅手机版4858 16代码

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

    __uint32_t events;      // Epoll events

美高梅手机版4858 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是1个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事件的发出;参数表明:

美高梅手机版4858 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()系统调用提供二个机制来完成共同多元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,每1种对应等待分化的风浪。readfds中列出的文件讲述符被监视是不是有数据可供读取(固然读取操作实现则不会阻塞)。writefds中列出的公文讲述符则被监视是或不是写入操作完毕而不封堵。最终,exceptfds中列出的文本讲述符则被监视是或不是产生尤其,或许不能控制的多寡是或不是可用(那几个景况唯有使用于套接字)。那三类set可以是NULL,那种意况下select()不监视那1类事件。
select()成功再次回到时,每组set都被涂改以使它只包罗准备好I/O的文件讲述符。例如,假如有多少个文本描述符,值分别是柒和九,被放在readfds中。当select()重回时,如若七仍旧在set中,则那一个文件讲述符已经准备好被读取而不会堵塞。假使九1度不在set中,则读取它将或然会阻塞(笔者说只怕是因为数量恐怕刚刚在select再次回到后就可用,这种状态下,下一遍调用select()将重返文件讲述符准备好读取)。
第一个参数n,等于全部set中最大的不胜文件讲述符的值加一。由此,select()的调用者负责检查哪个文件讲述符拥有最大值,并且把这一个值加一再传递给第贰个参数。
timeout参数是2个指向timeval结构体的指针,timeval定义如下:

                 {

柒. 例证程序

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

                     

下边是一个简单Echo
Server的例证程序,麻雀虽小,伍脏俱全,还蕴藏了3个简单易行的超时检查机制,简洁起见未有做错误处理。

设若这么些参数不是NULL,则正是未有公文讲述符准备好I/O,select()也会在经过tv_sec秒和tv_usec皮秒后回来。当select()重返时,timeout参数的情形在分裂的系统中是未定义的,因而老是调用select()在此之前务必另行伊始化timeout和文书讲述符set。实际上,当前版本的Linux会自动修改timeout参数,设置它的值为剩余时间。因而,假使timeout被设置为伍秒,然后在文件讲述符准备幸好此之前经过了3秒,则那三回调用select()重回时tv_sec将变为2。
若是timeout中的多少个值都安装为0,则调用select()将及时回到,报告调用时怀有未决的风浪,但不等待其余随后的轩然大波。
文本讲述符set不会一向操作,1般接纳多少个帮手宏来管理。那允许Unix系统以祥和喜好的秘诀来兑现公文讲述符set。但多数系统都简单地贯彻set为位数组。FD_ZERO移除内定set中的全数文件讲述符。每三遍调用select()在此之前都应该先调用它。
fd_set
writefds;
FD_ZERO(&writefds);
FD_SET添加2个文件讲述符到钦定的set中,FD_CL途乐则从内定的set中移除三个文件讲述符:
FD_SET(fd,
&writefds); /* add ‘fd’ to the set */
FD_CLR(fd,
&writefds); /* oops, remove ‘fd’ from the set */
统筹精良的代码应该永远不选用FD_CL昂科威,而且事实上情形中它也真的很少被使用。
FD_ISSET测试三个文件讲述符是还是不是内定set的一片段。借使文件讲述符在set中则赶回3个非0整数,不在则重临0。FD_ISSET在调用select()再次回到之后采用,测试内定的公文讲述符是或不是准备好有关动作:
if
(FD_ISSET(fd, &readfds))
/*
‘fd’ is readable without blocking! */
因为文件讲述符set是静态创立的,它们对文件讲述符的最大数目强加了二个限制,能够放进set中的最大文件讲述符的值由FD_SETSIZE钦点。在Linux中,那一个值是拾二四。本章后边我们还将见到这几个界定的衍生物。
重回值和错误代码
select()成功时重返准备好I/O的文书讲述符数目,包含全部四个set。假设提供了timeout,再次来到值大概是0;错误时回来-1,并且安装errno为下边多少个值之1:
EBADF,给某些set提供了没用文件讲述符。
EINT奥迪Q7,等待时捕获到非确定性信号,能够重新发起调用。
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,而是利用了贰个独门的构造体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结构体内定了2个被监视的文书描述符,能够传递多少个结构体,提示poll()监视四个公文讲述符。各样结构体的events域是监视该公文讲述符的风云掩码,由用户来安装这几个域。revents域是文本讲述符的操作结果事件掩码。内核在调用再次来到时设置这几个域。events域中呼吁的其余事件都大概在revents域中回到。合法的轩然大波如下:
POLLIN,有数据可读。
POLL瑞鹰DNOLANDM,有一般数据可读。
POLL君越DBAND,有优先数据可读。
POLLPBMWX伍I,有急切数据可读。
POLLOUT,写多少不会导致短路。
POLLWLANDNO本田UR-VM,写普通数据不会造成短路。
POLLWRBAND,写优先数据不会招致短路。
POLLMSG,SIGPOLL新闻可用。
除此以外,revents域中还可能回到下列事件:
POLLE普拉多,内定的文件讲述符产生错误。
POLLHUP,钦定的公文讲述符挂起风浪。
POLLNVAL,钦点的文书讲述符违法。
这么些事件在events域中无意义,因为它们在适用的时候总是会从revents中回到。使用poll()和select()差异,你不需求显式地央浼极度情状报告。POLLIN
| POLLPEnclaveI等价于select()的读事件,POLLOUT |
POLLWRBAND等价于select()的写事件。POLLIN等价于POLL中华VDNOQashqaiM |
POLLPRADODBAND,而POLLOUT则等价于POLLWTiguanNO大切诺基M。
诸如,要同时监视一个文件讲述符是还是不是可读和可写,大家能够安装events为POLLIN
|
POLLOUT。在poll重回时,大家得以检查revents中的标志,对应于文件讲述符请求的events结构体。假设POLLIN事件棉被服装置,则文件讲述符能够被读取而不打断。假若POLLOUT被设置,则文件讲述符能够写入而不造成短路。这么些标志并不是排斥的:它们只怕被同时安装,表示这些文件讲述符的读取和写入操作都会不荒谬重返而不打断。timeout参数内定等待的皮秒数,无论I/O是还是不是准备好,poll都会重返。timeout钦定为负数值表示最棒超时;timeout为0提示poll调用立刻回去并列出准备好I/O的文本描述符,但并不等待别的的轩然大波。那种状态下,poll()就像是它的名字那样,1旦大选出来,马上再次来到。
再次来到值和错误代码
得逞时,poll()再次来到结构体中revents域不为0的文书讲述符个数;假若在逾期前从未有过此外交事务件发生,poll()重回0;退步时,poll()重回-①,并设置errno为下列值之1:
EBADF,一个或五个结构体中钦命的公文讲述符无效。
EFAULT,fds指针指向的地方超出进程的地方空间。
EINTEnclave,请求的事件从前爆发二个随机信号,调用能够重复发起。
EINVAL,nfds参数超出PLIMIT_NOFILE值。
ENOMEM,可用内部存款和储蓄器不足,不能做到请求。

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

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

Epoll的优点:
一.支撑2个历程打开大数据的socket描述符(FD)
    select
最不能够经得住的是三个历程所打开的FD是有早晚限制的,由FD_SETSIZE设置,私下认可值是204八。对于那一个急需协理的上万一而再数目标IM服务器来说肯定太少了。那时候你一是足以选择修改那么些宏然后再度编写翻译内核,不过资料也还要提议如此会带来互连网功能的减退,2是能够接纳多进度的缓解方案(古板的
Apache方案),可是即便linux上边成立进程的代价相比较小,但依然是不足忽略的,加上进程间数据同步远不比线程间同步的迅猛,所以也不是1种完美的方案。可是epoll则并未有这一个范围,它所帮助的FD上限是最大能够打开文件的多少,那些数字1般远超出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,效用相比还有多少的回落。但是1旦采纳idle
connections模拟WAN环境,epoll的频率就处于select/poll之上了。

三.采取mmap加快内核与用户空间的音讯传递。
   
那一点莫过于涉及到epoll的实际完成了。无论是select,poll依然epoll都急需内核把FD音讯文告给用户空间,怎么着制止不须求的内部存款和储蓄器拷贝就很要紧,在那点上,epoll是经过基础于用户空间mmap同一块内部存款和储蓄器达成的。而只要你想本人一样从2.伍基础就关切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函数的第叁个参数(TCP达成二回握手的数目包队列长度),也能够依据你平台内部存款和储蓄器大小动态调整。更甚至在两个数目包面数目巨大但还要每种数据包本人尺寸却不大的异样系统上尝试最新的NAPI网卡驱动架构。

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

                      {

  1. //     
  2. // a simple echo server using epoll in linux    
  3. //     
  4. // 2009-11-05    
  5. // 20一3-0叁-2二:修改了多少个难点,一是/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帮衬的句柄数是有限制的,
同时只帮助拾二多个,这么些是句柄集合限制的,固然超越那么些范围,很可能造成溢出,而且十二分不便于察觉难点,
TAF就现身过那一个题目,
调节和测试了n天,才发现:)当然能够因而修改linux的socket内核调整这几个参数。
epoll的个性:epoll对于句柄事件的选项不是遍历的,是事件响应的,正是句柄上事件来就随即挑选出来,不须求遍历整个句柄链表,因而功效格外高,内核将句柄用红黑树保存的。比较于select,epoll最大的益处在于它不会趁机监听fd数目的做实而下落效用。因为在基本中的select达成中,它是利用轮询来拍卖的,轮询的fd数目越来越多,自然耗费时间越多。并且,在linux/posix_types.h头文件有那般的扬言:
#define __FD_SETSIZE    1024
表示select最多而且监听拾二多少个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);

开创3个epoll的句柄,size用来告诉内核那几个监听的数码一共有多大。那些参数不相同于select()中的第二个参数,给出最大监听的fd+一的值。须求注意的是,当创设好epoll句柄后,它就是会占用一个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:表示对应的文本讲述符能够写;
EPOLLP奥迪Q5I:表示对应的文本讲述符有紧迫的多少可读(那里应该代表有带外数据来临);
EPOLLEHummerH第22中学华V:表示对应的文本讲述符产生错误;
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. }  

美高梅手机版4858 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);

                            }

                           

                           

                            ev1.data.fd=sockfd;
//设置用于读操作的公文讲述符

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

                           
epoll_ctl(epfd1,EPOLL_CTL_MOD,sockfd,&ev①); 
//修改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);             
//奇怪,2个client运营多个版本,每一回获得的甚至是同二个socket。改个名字也不行

      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;

}

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有