• 【网络编程】学习笔记06 I/O多路复用之epoll


    epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结果而不用迫使开发者每次等待事件之前都必须重新准备要被监听的文件描述符集合,另一个原因就是获取事件的时候,它无需遍历整个被监听的描述符集,只要遍历那些被IO事件唤醒而加入ready队列的描述符即可。

     

    epoll的server端:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<unistd.h>
     5 #include<errno.h>
     6 #include<pthread.h>
     7 #include<ctype.h>
     8 #include<sys/socket.h>
     9 #include<sys/epoll.h>
    10 #include<arpa/inet.h>
    11 
    12 #define SERV_PORT 9527
    13 #define MAXLINE 8192
    14 #define OPEN_MAX 5000
    15 
    16 int main(int argc,char *argv[])
    17 {
    18     int listenfd = 0,connfd = 0,sockfd,i;
    19     int n,num = 0;
    20     ssize_t nready,efd,res;
    21     char buf[MAXLINE], str[INET_ADDRSTRLEN];
    22     socklen_t clilen;
    23 
    24     struct sockaddr_in cliaddr,servaddr;
    25 
    26     listenfd = socket(AF_INET,SOCK_STREAM,0);
    27     int opt = 1;
    28     setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));  //端口复用
    29     memset(&servaddr,0,sizeof(servaddr));
    30     servaddr.sin_family = AF_INET;
    31     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    32     servaddr.sin_port = htons(SERV_PORT);
    33     bind(listenfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
    34     listen(listenfd,20);
    35 
    36     efd = epoll_create(OPEN_MAX);    //创建epoll模型,efd指向红黑树根节点
    37 
    38     struct epoll_event tep, ep[OPEN_MAX];       //tep:epoll_ctl参数,ep[]:epoll_wait参数;
    39     tep.events = EPOLLIN;
    40     tep.data.fd = listenfd;                     //指定listenfd的监听事件为“读”
    41 
    42     res = epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &tep); //将listenfd及对应的结构体设置到树上,efd可找到该树
    43 
    44     for(;;){
    45         //epoll为server阻塞监听事件,ep为struct epoll_event类型数组,OPEN_MAX为数组容量,-1表示永久阻塞
    46         nready = epoll_wait(efd,ep,OPEN_MAX,-1);
    47 
    48         for(i=0;i<nready;i++){
    49             if(!(ep[i].events & EPOLLIN))
    50                 continue;
    51             if(ep[i].data.fd == listenfd){      //判断满足事件的fd是不是lfd
    52                 clilen = sizeof(cliaddr);
    53                 connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen); //接受连接
    54 
    55                 tep.events = EPOLLIN; 
    56                 tep.data.fd = connfd;
    57 
    58                 res = epoll_ctl(efd,EPOLL_CTL_ADD,connfd,&tep);  //加入红黑树
    59             }else{                      //不是lfd
    60                 sockfd = ep[i].data.fd;
    61                 n = read(sockfd,buf,MAXLINE);
    62 
    63                 if(n == 0){                                            //读到0,说明客户端关闭连接
    64                     res = epoll_ctl(efd, EPOLL_CTL_DEL, sockfd, NULL); //将该文件描述符从红黑树摘除
    65                     close(sockfd);                                     //关闭与该客户端的连接
    66                 }
    67                 else if(n < 0){        //出错
    68                     res = epoll_ctl(efd, EPOLL_CTL_DEL, sockfd, NULL); //摘除节点
    69                     close(sockfd);
    70                 }
    71                 else{                  //读到了字节数
    72                     for(i=0;i<n;i++)
    73                        buf[i] = toupper(buf[i]);
    74 
    75                     write(STDOUT_FILENO,buf,n);
    76                     write(sockfd,buf,n);
    77                 }
    78             }
    79         }
    80     }
    81     close(listenfd);
    82     return 0;
    83 }
    View Code
    前ICPC算法竞赛退役选手|现摸鱼ing
  • 相关阅读:
    05、汇编语言--环境搭建
    04、计算机基础--编码
    03、计算机基础--数制
    02、计算机基础--8086处理器
    01、计算机基础--计算机概述
    06、JavaEE--SpringMVC
    04、Android系统--Android10
    03、Android系统--Android4.4
    App自动化测试工具Uiautomator2
    Python yaml文件读写
  • 原文地址:https://www.cnblogs.com/Anonytt/p/15547536.html
Copyright © 2020-2023  润新知