【网络编程】学习笔记--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

 

posted @ 2021-11-13 11:14  Anonytt  阅读(36)  评论(0编辑  收藏  举报