**
epoll原理
**
调用epoll_create时:
1.内核在epoll文件系统里创建了file结点;
2.内核cache里新建了个红黑树以便存储以后epoll_ctl传来的fd;
3.同时建立了list就绪链表,即存储准备就绪的事件。
调用epoll_ctl时:
1.把fd挂到epoll文件系统的file对象里红黑树上;
2.同时在内核中断处理程序注册一个回调函数,内核便会在这个句柄的中断到达时立即把它放到list就绪链表里。
调用epoll_wait时,做了以下事情:
1.观察list链表。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。
2.注意:即使我们要监控很多的描述符,多数情况下一次也只返回较少量的准备就绪描述符,即epoll_wait仅需要从内核态复制少量的描述符到用户态.
总结如下:
红黑树+就绪链表+少量的内核cache =解决了大并发下的socket处理问题
func.h
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/stat.h>
5 #include<unistd.h>
6 #include<sys/types.h>
7 #include<dirent.h>
8 #include<time.h> //ctime
9 #include<pwd.h>
10 #include<grp.h> //用户名
11 #include<fcntl.h> //文件描述符
12 #include<sys/mman.h> //mmap
13 #include<sys/select.h>//IO多路复用
14 #include<sys/time.h>//IO多路复用
15 #include <sys/wait.h>//wait
16 #include <sys/ipc.h>//shared memory
17 #include <sys/shm.h>//shared memory
18 #include <sys/sem.h>//semaphore
19 #include<sys/msg.h>//message queue
20 #include<signal.h>//signa
21 #include<pthread.h>//thread
22 #include <netinet/in.h>//net
23 #include <sys/socket.h>
24 #include <netdb.h>//gethostbyname
25 #include<arpa/inet.h>
26 #include<sys/epoll.h>//epoll
27 #include<sys/uio.h>//writev
28 #define ARGS_CHECK(argc,val) {if(argc!=val){printf("error args\n");return -1 ;}}
29 #define ERROR_CHECK(ret,retVal,funcName) {if(ret==retVal){perror(funcName);return -1;}}//如果p==NULL,perro(fopen)
30 #define THREAD_ERROR_CHECK(ret,funcName) {if(ret!=0){printf("%s:%s\n",funcName,strerror(ret));return -1;}}
31 #define CHILD_THREAD_ERROR_CHECK(ret,funcName) {if(ret!=0){printf("%s:%s\n",funcName,strerror(ret));return (void*)-1;}}
1 #include <func.h>
2
3 int tcpInit(int *sfd,char* ip,char *port){
4 int socket_fd = socket(AF_INET,SOCK_STREAM,0);//IPV4,TCP,0
5 ERROR_CHECK(socket_fd,-1,"socket");
6 struct sockaddr_in ser_addr;
7 bzero(&ser_addr,sizeof(ser_addr));
8 ser_addr.sin_family = AF_INET;
9 ser_addr.sin_port = htons(atoi(port));
10 ser_addr.sin_addr.s_addr = inet_addr(ip);
11 int reuse = 1;
12 int ret;
13 ret = setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(int));
14 ERROR_CHECK(ret,-1,"setsockopt");
15 ret = bind(socket_fd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
16 ERROR_CHECK(ret,-1,"bind");
17 listen(socket_fd,10);
18 *sfd = socket_fd;//return
19 return 0;
20 }
1 #include <func.h>
2 int setNonBlock(int fd){
3 int status = fcntl(fd,F_GETFL);
4 printf("status default:%d\n",status);
5 status = status|O_NONBLOCK;
6 printf("status :%d\n",status);
7 fcntl(fd,F_SETFL,status);
8 return 0;
9 }
1 #include <func.h>
2 int tcpInit(int *,char*,char*);
3 int setNonBlock(int);
4 int main(int argc,char *argv[])
5 {
6 ARGS_CHECK(argc,3);
7 int socket_fd;
8 int ret = tcpInit(&socket_fd,argv[1],argv[2]);
9 ERROR_CHECK(ret,-1,"tcpInit");
10 //When addr is NULL, nothing is filled in; in this case,
11 //addrlen is not used, and should also be NULL.
12 int new_fd;
13 char buf[10] = {0};
14 int ep_fd = epoll_create(1);
15 ERROR_CHECK(ep_fd,-1,"epoll_create");
16 struct epoll_event event,evs[2];
17 event.events = EPOLLIN;//|EPOLLET;
18 event.data.fd = STDIN_FILENO;
19 ret = epoll_ctl(ep_fd,EPOLL_CTL_ADD,STDIN_FILENO,&event);
20 ERROR_CHECK(ret,-1,"epoll_ctl");
21 event.data.fd = socket_fd;//&event是传入参数
22 ret = epoll_ctl(ep_fd,EPOLL_CTL_ADD,socket_fd,&event);
23 ERROR_CHECK(ret,-1,"epoll_ctl");
24 int ready_fd_count;
25 while(1){
26 ready_fd_count = epoll_wait(ep_fd,evs,2,-1);//-1 wait ∞
27 printf("ready_fd_count:%d\n",ready_fd_count);
28 printf("evs[0].data.fd is %d, evs[1].data.fd %d\n",evs[0].data.fd,evs[1].data.fd);
29 for(int i = 0;i<ready_fd_count;i++)
30 {
31 if(evs[i].data.fd == socket_fd)
32 {
33 new_fd = accept(socket_fd,NULL,NULL);
34 ERROR_CHECK(new_fd,-1,"accept");
35 event.data.fd = new_fd;
36 ret = epoll_ctl(ep_fd,EPOLL_CTL_ADD,new_fd,&event);
37 ERROR_CHECK(ret,-1,"epoll_ctl");
38 setNonBlock(new_fd);
39 }
40 if(evs[i].data.fd == STDIN_FILENO)
41 {
44 bzero(buf,sizeof(buf));
45 ret = read(STDIN_FILENO,buf,sizeof(buf));
46 if(0 == ret)
47 {
48 puts("byebye");
49 break;
50 }
52
53 send(new_fd,buf,strlen(buf)-1,0);
54
55
56
57 }
58 if(evs[i].data.fd == new_fd)
59 {
60 for(;;)
61 {
62 bzero(buf,sizeof(buf));
63 ret = recv(new_fd,buf,sizeof(buf),0);
64 if(0 == ret)
65 {
66 puts("byebye");
67 event.data.fd = new_fd;
68 ret = epoll_ctl(ep_fd,EPOLL_CTL_DEL,new_fd,&event);
69 ERROR_CHECK(ret,-1,"epoll_ctl");
70 close(new_fd);
71 break;
72 }else if(-1 == ret ){
73 break;
74 }else{
75 printf("%s",buf);
76 }
77 }
78 printf("\n");
79 }
80 }
81 }
82 return 0;
83 }