多路复用I/O模型epoll() 模型 代码实现

多路复用I/O模型epoll() 模型 代码实现

epoll模型

int epoll_create(int maxevent) //创建一个epoll的句柄 然后maxevent表示监听的数目的大小
int epoll_ctl(int epollfd,int op,int fd,struct epoll_event *event) //epoll的事件注册函数
/*
epollfd 为epoll_create()的返回值
op 表示为相应的操作
fd 为套接字
*event 表示监听什么事件
*/
OP 有
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删除一个fd;


int epoll_wait(int epollfd,struct epoll_event *event,int maxevents,int timeout);
/*
epollfd epoll_create的返回值
*event 从内核得到时间的集合
maxevents 告诉内核event多大 不能大于epoll_create()中的maxevent
timeout 表示等待的时间-1表示阻塞 0表示立即返回
*/

epoll_event结构体

1 struct epoll_event {
2   __uint32_t events;  /* Epoll events */
3   epoll_data_t data;  /* User data variable */
4 };
1 typedef union epoll_data
2 {
3   void *ptr;
4   int fd;
5   uint32_t u32;
6   uint64_t u64;
7 } epoll_data_t;

其中epoll_event 结构体中的events参数的值是宏定义:

EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

data.h

 1 #ifndef DATA_H
 2 #define DATA_H
 3 #include <string.h>
 4 #include <stdio.h>
 5 #include <sys/epoll.h>
 6 #include <sys/stat.h>
 7 #include <stdlib.h>
 8 #include <errno.h>
 9 #include <netinet/in.h>
10 #include <sys/socket.h>
11 #include <unistd.h>
12 #include <arpa/inet.h>
13 #include <assert.h>
14 #include <sys/types.h>
15 
16 #define IP "127.0.0.1"
17 #define PORT 4578
18 #define maxn 1100
19 #define MAXLINE 100
20 #define BACKLOG 5
21 #define EPOLLEVENTS 1120
22 #define _EVENTS 100
23 #endif

server.c

  1 #include "data.h"
  2 static void epoll_accept(int sockfd);
  3 static void submit_to_check(int epollfd,struct epoll_event *events,int num,int sockfd,char *buf);
  4 static void submit_to_read(int epollfd,int conn,char *buf);
  5 static void submit_to_write(int epollfd,int conn,char *buf);
  6 static void submit_to_accept(int epollfd,int conn);
  7 static void change_event(int epollfd,int conn,int  ser_event);
  8 static void change_delete(int epollfd,int conn,int ser_event);
  9 static void add_event(int epollfd,int sockfd,int  ser_event);
 10 
 11 static int init()
 12 {
 13     int sockfd;
 14     struct sockaddr_in server_in;
 15     if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
 16     {
 17         fprintf(stderr,"socket fail,error %s",strerror(errno));
 18         return -1;
 19     }
 20     bzero(&server_in,sizeof(server_in));
 21     server_in.sin_family = AF_INET;
 22     server_in.sin_port = htons(PORT);
 23     inet_pton(AF_INET,IP,&server_in.sin_addr);
 24     if(bind(sockfd,(struct sockaddr*)&server_in,sizeof(server_in)) == -1)
 25     {
 26         fprintf(stderr,"bind fail,error %s",strerror(errno));
 27         return -1;
 28     }
 29     listen(sockfd,BACKLOG);
 30     return sockfd;
 31 }
 32 
 33 static void epoll_accept(int sockfd)
 34 {
 35     int epollfd;
 36     char buf[maxn];
 37     memset(buf,0,sizeof(buf));
 38     struct epoll_event events[_EVENTS];
 39     epollfd = epoll_create(EPOLLEVENTS);
 40     int ret;
 41     add_event(epollfd,sockfd,EPOLLIN);
 42     for(;;)
 43     {
 44         ret = epoll_wait(epollfd,events,_EVENTS,-1);
 45         submit_to_check(epollfd,events,ret,sockfd,buf);
 46     }
 47     close(epollfd);
 48 }
 49 static void submit_to_check(int epollfd,struct epoll_event *events,int num,int sockfd,char *buf)
 50 {
 51     int i;
 52     int fd;
 53     for(i=0;i<num;i++)
 54     {
 55         fd = events[i].data.fd;
 56         if((fd == sockfd) && (events[i].events&EPOLLIN))
 57         {
 58             submit_to_accept(epollfd,sockfd);
 59         }    
 60         else if(events[i].events & EPOLLIN)
 61                     {
 62                                 submit_to_read(epollfd,fd,buf);
 63                     }
 64         else if(events[i].events & EPOLLOUT)
 65         {
 66             submit_to_write(epollfd,fd,buf);
 67         }
 68     }
 69 }
 70 static void submit_to_read(int epollfd,int conn,char *buf)
 71 {
 72     int n;
 73     n = read(conn,buf,maxn);
 74     if(n == 0)
 75     {
 76         fprintf(stderr,"client close!
");
 77         close(conn);
 78         change_delete(epollfd,conn,EPOLLIN);
 79     }
 80     else if(n == -1)
 81     {
 82         fprintf(stderr,"read error
");
 83         close(conn);
 84         change_delete(epollfd,conn,EPOLLIN);
 85     }
 86     else
 87     {
 88         fprintf(stderr,"read message is %s
",buf);
 89         change_event(epollfd,conn,EPOLLOUT);
 90     }
 91 }
 92 static void submit_to_write(int epollfd,int conn,char *buf)
 93 {
 94     int n;
 95     n = write(conn,buf,strlen(buf));
 96     if(n == -1)
 97     {
 98         printf("server closed!
");
 99         close(conn);
100         change_delete(epollfd,conn,EPOLLOUT);
101     }
102     else
103     {
104         change_event(epollfd,conn,EPOLLIN);
105     }
106     memset(buf,'