C语言实现:epoll的边沿触发模式/非阻塞模式实现即时聊天(linux环境)

**

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 }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值