1.原因

  1.原因

村办对于epollhup的精通,个人epollhup了然

  1.原因

    由于最近对此异步connect函数的测试,发现提前将四个套接字参预epoll监听队列会不断爆出epollhup事件

  2.示例

    ……..

     iEpoll = epoll_create(1);

     iFd = socket(AF_INET, SOCK_STREAM, 0);

          stEvent.events = EPOLL_IN;

澳门金沙国际,     stEvent.data.u32 = iFd;

 

    epoll_ctl(iEpoll, EPOLL_CTL_ADD, iFd, &stEvent);

    i = epoll_wait(iEpoll, astEvent, 1, -1);

    ……………….

  3.调试

民用对于epollhup的驾驭,UNIX互连网编程学习指南。    在该tcp套接字创制之后,还未建链,也从不listen,表达那种情景下不会有其他事件上报,那么将这么的一个套接字加入该listen队列是谬误的,但是epoll_ctl时加入却是成功的,很令人费解.固然三番五次的操作中有把该套接字connect只怕listen,然而由于水平触发事件的原委,此前的事件未被拍卖,将促成那几个hup事件直接上报.

  4.解决

    以上剖析表明将二个不容许触发该事件暴发暴发的套接字参预epoll,将会招致hup事件的汇报,所以接受该事件时,二个办法是将套接字移出epoll监听队列,另一个主意是,在connect操作之后依然在listen之后,再将该套接字参预epoll

 

1.原因
由于近来对此异步connect函数的测试,发现提前将贰个套接字参预epoll监听队列会不断爆出epo…

epoll是select/poll的加深版,都是多路复用的函数,epoll有了不小的一字不苟。

    由于近年来对于异步connect函数的测试,发现提前将三个套接字出席epoll监听队列会不断爆出epollhup事件

    由于近来对于异步connect函数的测试,发现提前将三个套接字出席epoll监听队列会不断爆出epollhup事件

epoll的功能

① 、支持监听大数据的socket描述符
3个进度内,select能打开的fd是有限量的,有宏FD_SETSIZE设置,暗中同意值是1024.z在少数时候,那一个数值是远远不够用的。化解措施有两种,已是修改宏然后再重复编译内核,但与此同时会挑起网络成效的狂跌;二是行使多进程来消除,不过创立四个经过是有代价的,而且经过间数据同步没有二十八线程间方便。而epoll没有那么些限制,它所扶助的最大FD上限远远大于1024,在1GB内存的机器上是10万左右(具体数据足以再cat
/proc/sys/file_max查看);

② 、功用的进步

select函数每一趟都当监听的套接组有事件时就回到,但却不可以讲有事件发生的套接字筛选出来,而是改变其在套接组的标志量,所以每便监听到事件,都亟待将套接组整个遍历2遍。时间复杂度是O(n)。当FD数目扩大时,效用会线性下跌。
而epoll,每一趟会将监听套接字中爆发时间的套接字加到一列表中,然后大家得以直接对此列表举办操作,而并未生出事件的套接字会被过滤掉,极大地升高了IO功用。这点进一步在套接字监听数据巨大而活泼数量少的时候很分明。

  2.示例

  2.示例

epoll的用法

epoll是使用首要在于两个函数。

1、int epoll_create(int size);

创办3个epoll句柄,size用来告诉内核那几个监听的多少最大值。注意:size是数量的最大值,不是fd的最大值
当成立好epoll句柄后,它就是会占用2个fd值,所以在利用完epoll后,必须选择close()关闭,否则或者引致fd被耗尽。

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

epoll的风浪注册函数。
epfd是epoll的句柄,即epoll_create的重临值。
op代表动作:用多少个宏表示:
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD: 修改已经登记的fd的监听事件;
EPOLL_CTL_DEL: 从epfd中删去三个fd;
fd是索要监听的套接字描述符;
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_data_t data;
};

events可以是以下几个宏的聚众:
EPOLLIN: 表示对应的公文讲述符可以读(包蕴对端SOCKET符合规律关闭);
EPOLLOUT: 表示对应的文本讲述符可以写;
EPOLLPSportageI:
表示对应的文本讲述符有热切的数据可读(那里代表有带外数据来临);
EPOLLELX570大切诺基: 表示对应的文本讲述符发生错误;
EPOLLHUP: 表示对应的文书讲述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge
Triggered)情势,那是绝对于水平触发(Level Triggered)的。
EPOLLONESHOT:
只监听3次事件,当监听完这一次事件随后,就会把这一个fd从epoll的队列中除去,借使还亟需继续监听这些socket的话,须求再一次把这几个fd插足到EPOLL队列里。

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

等候事件的爆发,重返必要处理的轩然大波的数码,并将需处总管件的套接字集合与参数events内,可以遍历events来处管事人件。
参数epfd为epoll句柄。
events为事件集合。
参数timeout是过期时间(皮秒,0立刻重临,-1是恒久阻塞)。该函数再次来到须求处理的轩然大波,如重临0表示已过期。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>


#define MAXLINE 10
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 8888
#define INFTIN 1000
#define IP_ADDR "192.168.1.94"


int main()
{
    struct epoll_event ev, events[20];
    struct sockaddr_in clientaddr, serveraddr;
    int epfd;
    int listenfd;   //监听fd
    int nfds;
    int i, n;
    int sock_fd, conn_fd;
    char buf[MAXLINE];
    socklen_t clilen;

    epfd = epoll_create(256);    //生成epoll句柄
    listenfd = socket(AF_INET, SOCK_STREAM, 0);   //创建套接字
    ev.data.fd = listenfd;       //设置与处理事件相关的文件描述符
    ev.events = EPOLLIN;   //设置要处理的事件类型

    epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);   //注册epoll事件

    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(SERV_PORT);
    bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));  //绑定套接口

    listen(listenfd, LISTENQ);    //转为监听套接字

    while(1)
    {
        nfds = epoll_wait(epfd, events, 20, 500);   //等待事件发生
        for(i=0; i<nfds; ++i)
        {
            if(events[i].data.fd == listenfd)  //有新的连接
            {
                clilen = sizeof(struct sockaddr_in);
                conn_fd = accept(listenfd, (struct sockaddr*)&clientaddr, &clilen);
                printf("accept a new client: %s\n", inet_ntoa(clientaddr.sin_addr));
                ev.data.fd = conn_fd;
                ev.events = EPOLLIN;   //设置监听事件为可写
                epoll_ctl(epfd, EPOLL_CTL_ADD, conn_fd, &ev);   //新增套接字
            }
            else if(events[i].events & EPOLLIN) //可读事件
            {
                if((sock_fd = events[i].data.fd) < 0)
                    continue;
                if((n = recv(sock_fd, buf, MAXLINE, 0)) < 0)
                {
                    if(errno == ECONNRESET)
                    {
                        close(sock_fd);
                        events[i].data.fd = -1;
                    }
                    else
                    {
                        printf("readline error\n");
                    }
                }
                else if(n == 0)
                {
                    close(sock_fd);
                    printf("关闭\n");
                    events[i].data.fd = -1;
                }

                printf("%d--> %s\n", sock_fd, buf);
                ev.data.fd =  sock_fd;
                ev.events = EPOLLOUT;
                epoll_ctl(epfd, EPOLL_CTL_MOD, sock_fd, &ev);   //修改监听事件为输出
            }
            else if(events[i].events & EPOLLOUT) //可写事件
            {
                sock_fd = events[i].data.fd;
                printf("out:\n");
                scanf("%s", buf);
                ev.events = EPOLLIN;
                epoll_ctl(epfd, EPOLL_CTL_MOD, sock_fd, &ev);
            }
        }
    }
    return 0;
}

<a
href=””
style=”color: red”>[Linux-C网络编程之epoll函数]

[epoll详解]

《深刻掌握Nginx模块开发与架构解析》9.6小节

    ……..

    ……..

     iEpoll = epoll_create(1);

     iEpoll = epoll_create(1);

     iFd = socket(AF_INET, SOCK_STREAM, 0);

     iFd = socket(AF_INET, SOCK_STREAM, 0);

          stEvent.events = EPOLL_IN;

          stEvent.events = EPOLL_IN;

     stEvent.data.u32 = iFd;

     stEvent.data.u32 = iFd;

 

 

    epoll_ctl(iEpoll, EPOLL_CTL_ADD, iFd, &stEvent);

    epoll_ctl(iEpoll, EPOLL_CTL_ADD, iFd, &stEvent);

    i = epoll_wait(iEpoll, astEvent, 1, -1);

    i = epoll_wait(iEpoll, astEvent, 1, -1);

    ……………….

    ……………….

  3.调试

  3.调试

    在该tcp套接字创立之后,还未建链,也没有listen,表明那种场地下不会有其它事件上报,那么将这么的一个套接字参与该listen队列是不当的,不过epoll_ctl时参与却是成功的,很令人费解.即便一而再的操作中有把该套接字connect可能listen,可是出于水平触发事件的原由,以前的风浪未被处理,将造成那个hup事件直接上报.

    在该tcp套接字创制之后,还未建链,也不曾listen,表明那种场地下不会有其余事件上报,那么将那样的一个套接字插足该listen队列是一无所长的,不过epoll_ctl时进入却是成功的,很令人费解.尽管两次三番的操作中有把该套接字connect恐怕listen,然而由于水平触发事件的案由,之前的轩然大波未被拍卖,将导致那几个hup事件直接上报.

  4.解决

  4.解决

    以上分析表达将三个无法触发该事件爆发暴发的套接字参加epoll,将会导致hup事件的报告,所以吸收该事件时,三个措施是将套接字移出epoll监听队列,另三个艺术是,在connect操作之后如故在listen之后,再将该套接字出席epoll

    以上剖析表达将3个不容许触发该事件发生暴发的套接字加入epoll,将会造成hup事件的反映,所以接受该事件时,二个措施是将套接字移出epoll监听队列,另二个艺术是,在connect操作之后如故在listen之后,再将该套接字参预epoll

 

 

相关文章