• 6、epoll多路IO


    epoll多路IO

    1、poll函数的参数

    int poll(strucf pollfd  *fds, nfds_t nfds, int timeout);
    /*
    		fds:监听的文件描述数组
    		struct pollfd
    		{
    			int fd;
    			short events;//传入事件,取值POLLIN,POLLOUT,POLLERROR
    			short revents;//传出事件,传入时给0,。如果满足对应事件的话,返回非0
    						  //POLLIN,POLLOUT,POLLERRO
    		}
    		nfds:监听数组的实际有效监听个数
    		timeout:超时时长,单位:毫秒(-1,阻塞等待;0,立即返回; >0:等待时长)
    		返回值:返回满足对应监听的文件描述符的总个数
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2、poll函数使用的注意事项

    server
    poll
    cfd1
    cfd2
    cfd3
    struct pollfd pfds[1024];
    pfds[0].fd = lfd;
    pfds[0].events = POLLIN;
    pfds[0].revents = 0;
    
    pfds[1].fd = lfd;
    pfds[1].events = POLLIN;
    pfds[1].revents = 0;
    
    pfds[2].fd = lfd;
    pfds[2].events = POLLIN;
    pfds[2].revents = 0;
    
    while(1)
    {
        int ret = poll(pfds,5,-1);
        for(i = 0; i < 5; i++)
        {
         	if(pfds[i].revents & POLLIN)
            {
                accept();//如果是lfd
                /***如果是cfd***/
                write()/read();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    3、poll总结

    优点:自带数组结构,可以将监听时间和返回事件集合

    ​ 可以扩展监听上限(select监听上限无法修改,但是poll可以修改监听上限)

    缺点:不能跨平台,只能在linux下用

    ​ 无法直接定位满足监听事件文件描述符,编码难度较大

    4、突破1024限制

    突破1024文件描述符限制:

    cat  /proc/sys/fs/file-max;     //当前计算机所能打开的最大文件个数,受硬件影响 
    ulimit -a;//当前用户下的进程,默认打开文件
    cat /proc/sys/fs/file-max  //查看一个socket能打开的fd上限
    
    • 1
    • 2
    • 3

    5、epoll函数

    创建红黑树:

    int epoll_create(int size);//打开一个句柄,文件描述符指向一个平衡二叉树,即epfd
    //size指创建红黑树的监听节点的数量。(仅供内核参考)
    //返回指,指向平衡二叉树的跟节点,失败就是-1
    
    • 1
    • 2
    • 3
    epfd
    lfd
    cdf2
    cfd1

    监听红黑树:

    int epollctl(int epfd, int op, int fd, struct epoll_event *event);
    //用来控制红黑树
    //op表示对红黑树所做的操作
    //	EPOLL_CTL_ADD  添加fd到监听红黑树
    //  EPOLL_CTL_MOD  修改fd在红黑树的监听事件
    //	EPOLL_CTL_DEL  摘下fd
    //fd表示待监听的fd
    //event: 本质上是struct epoll_event 结构体地址
    //	events:  EPOLLIN/EPOLLOUT/EPOLLERR
    //  data:联合体  int fd:	对应监听事件的fd
    //				void *ptr: 泛型指针
    //              uint32_t  u32;
    //              uint64_t  u64;
    //返回值: 成功0;失败 -1 eorr
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    阻塞红黑树:

    int epoll_wait(int epfd, struct epoll_events *events, int maxevents, int timeout);
    //epfd:  句柄
    //events:  [数组],传出参数,满足监听条件的那些fd结构体
    //用epoll监听的话监听的就不止是lfd,有数组就不需要轮询所有fd时间了
    //maxevents:数组中元素的总数量
    //timeout:-1阻塞,0:不阻塞,>0超时时间
    //返回值:
    //   > 0:满足监听的总个数。可以用作循环上限
    //    0 :没有fd满足事件
    //    -1:出错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6、epoll多路IO的代码实现

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    
    #define MAXLINE  8192
    #define SERV_PORT 8000
    #define OPEN_MAX 5000
    
    int main(int argc, char *argv[])
    {
        int i,lfd,cfd,sockfd;
        int n,num = 0;
        size_t nready,efd,res;
        char buf[MAXLINE],str[INET6_ADDRSTRLEN];
        socklen_t clien;
    
        struct sockaddr_in cliaddr,servaddr;
        struct epoll_event tep, ep[OPEN_MAX];//epoll_ctl para
    
        lfd = socket(AF_INET,SOCK_STREAM,0);
        int opt = 1;
        setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//port reuse
        bzero(&servaddr,sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(SERV_PORT);
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        bind(lfd,(struct sockaddr *) &servaddr, sizeof(servaddr));
        listen(lfd,20);
        efd = epoll_create(OPEN_MAX);
        tep.events = EPOLLIN; tep.data.fd = lfd;
        res = epoll_ctl(efd,EPOLL_CTL_ADD,lfd,&tep);
        for(;;)
        {
            nready = epoll_wait(efd,ep,OPEN_MAX,-1);
            for(i = 0; i < nready; i++)
            {
                if(!(ep[i].events & EPOLLIN))
                    continue;
                if(ep[i].data.fd == lfd)
                {
                    clien = sizeof(cliaddr);
                    cfd = accept(lfd,(struct sockaddr *)&cliaddr, &clien);
                    tep.events = EPOLLIN;
                    tep.data.fd = cfd;
                    res = epoll_ctl(efd,EPOLL_CTL_ADD,cfd,&tep);
                }
                else
                {   
                    sockfd = ep[i].data.fd;
                    n = read(sockfd,buf,MAXLINE);
                    if(n <= 0)
                    {
                        res = epoll_ctl(efd,EPOLL_CTL_DEL,sockfd,NULL);
                        close(sockfd);
                    }
                    else
                    {
                        for(i = 0; i < n; i++)
                        {
                            buf[i] = toupper(buf[i]);
                        }
                        write(STDOUT_FILENO,buf,n);
                        write(sockfd,buf,n);
                    }
                }
            }
        }
        close(lfd);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
  • 相关阅读:
    【每日一题】调整搜索二叉树中两个错误的节点
    JAVA生成带图标的二维码(产品溯源码)
    java毕业生设计医院取药系统计算机源码+系统+mysql+调试部署+lw
    非关系型数据库MongoDB的特点及安装
    WSL Ubuntu + Docker Desktop搭建python环境
    Slimming剪枝方法
    Superset 1.2.0 安装
    mybatis自定义插件
    Java类的定义及定义类时可用的关键字
    聊聊什么是分布式事务
  • 原文地址:https://blog.csdn.net/misikamikirto/article/details/133761261