epoll

来源:互联网 发布:adobe软件都是干嘛的 编辑:程序博客网 时间:2024/06/05 11:20

     select和poll被鄙视得厉害, 因为有了Linux epoll的存在。 网上讲解select/poll/epoll的例子不胜枚举, 各种比喻, 各种图示。 其实, epoll并没有那么玄乎。 本文中, 我们不进行画图讲解, 也尽量避免过多的文字描述, 只是初步来感受一下epoll.

        服务端代码为:

[cpp] view plain copy
  1. #include <unistd.h>  
  2. #include <sys/types.h>  
  3. #include <sys/socket.h>  
  4. #include <netdb.h>  
  5. #include <stdio.h>  
  6. #include <stdlib.h>  
  7. #include <string.h>  
  8. #include <ctype.h>  
  9. #include <errno.h>  
  10. #include <malloc.h>  
  11. #include <netinet/in.h>  
  12. #include <arpa/inet.h>  
  13. #include <sys/ioctl.h>  
  14. #include <stdarg.h>  
  15. #include <fcntl.h>  
  16. #include <fcntl.h>  
  17. #include <sys/poll.h>  
  18. #include <sys/epoll.h>  
  19. #define BACKLOG 100    
  20.   
  21. int main()    
  22. {  
  23.     int iListenSock = socket(AF_INET, SOCK_STREAM, 0);  
  24.     sockaddr_in addr;  
  25.     memset(&addr, 0, sizeof(addr));  
  26.     inet_aton("0.0.0.0", &addr.sin_addr);  
  27.     addr.sin_family = AF_INET;  
  28.     addr.sin_port = htons(8888);  
  29.   
  30.     int iOpt = 1;  
  31.     setsockopt(iListenSock, SOL_SOCKET, SO_REUSEADDR, &iOpt, sizeof(iOpt)); // 标配  
  32.     bind(iListenSock, (sockaddr*)&addr, sizeof(addr));  
  33.     listen(iListenSock, BACKLOG);  
  34.     
  35.     epoll_event ev;  
  36.     ev.data.fd = iListenSock;  
  37.     ev.events = EPOLLIN;  
  38.       
  39.     epoll_event events[BACKLOG + 1];  
  40.   
  41.     int epollFD = epoll_create(BACKLOG + 1);   // 告诉内核监测的数目, 返回的epollFD为epoll管理句柄  
  42.     epoll_ctl(epollFD, EPOLL_CTL_ADD, iListenSock, &ev);  // 将ev和对应的iListenSock添加到epoll句柄,用于被epollFD管理  
  43.     while(1)   
  44.     {  
  45.         int timeoutMS = -1; // 永不超时  
  46.         int nfds = epoll_wait(epollFD, events, BACKLOG + 1, timeoutMS);   // events和nfds是一对输出值  
  47.         printf("nfds is %d\n", nfds);  
  48.           
  49.         for(int i = 0; i < nfds; i++)   
  50.         {    
  51.             if(events[i].data.fd == iListenSock)         // 用于监听客户端连接的socket  
  52.             {    
  53.                 int iConnSock = accept(iListenSock, NULL, NULL);  
  54.                 if (iConnSock < 0)  
  55.   
  56.                 {  
  57.                     continue;  
  58.                 }  
  59.   
  60.                 ev.data.fd = iConnSock;  
  61.                 ev.events = EPOLLIN;  
  62.                 epoll_ctl(epollFD, EPOLL_CTL_ADD, iConnSock, &ev);  // 将ev和对应的iListenSock添加到epoll句柄,用于被epollFD管理  
  63.   
  64.                 printf("new sock came, fd is %d\n", iConnSock);  
  65.             }   
  66.             else   
  67.             {  
  68.                 int iConnSock = events[i].data.fd;      // 用于通信的socket  
  69.                 char szBuf[1024] = {0};  
  70.                 int recvLen = recv(iConnSock, szBuf, sizeof(szBuf) - 1, 0);  
  71.                 if (recvLen > 0)   
  72.                 {    
  73.                     printf("recv data [%s] from fd [%d]\n", szBuf, iConnSock);  
  74.                 }  
  75.                 else if(0 == recvLen)  
  76.                 {    
  77.                     ev.data.fd = iConnSock;  
  78.                     epoll_ctl(epollFD, EPOLL_CTL_DEL, iConnSock, &ev);  
  79.                     close(iConnSock);  
  80.                     printf("connection closed, local fd is [%d]\n", iConnSock);  
  81.                 }  
  82.                 else  
  83.                 {  
  84.                     ev.data.fd = iConnSock;  
  85.                     epoll_ctl(epollFD, EPOLL_CTL_DEL, iConnSock, &ev);  
  86.                     close(iConnSock);  
  87.                     printf("recv error, local fd is [%d]\n", iConnSock);  
  88.                 }  
  89.             }    
  90.         }    
  91.     }    
  92.       
  93.     close(epollFD);  
  94.     close(iListenSock);  
  95.     return 0;  
  96. }    
        客户端代码为:

[cpp] view plain copy
  1. #include <unistd.h>  
  2. #include <sys/types.h>  
  3. #include <sys/socket.h>  
  4. #include <netdb.h>  
  5. #include <stdio.h>  
  6. #include <stdlib.h>  
  7. #include <string.h>  
  8. #include <ctype.h>  
  9. #include <errno.h>  
  10. #include <malloc.h>  
  11. #include <netinet/in.h>  
  12. #include <arpa/inet.h>  
  13. #include <sys/ioctl.h>  
  14. #include <stdarg.h>  
  15. #include <fcntl.h>  
  16. #include <fcntl.h>  
  17.   
  18. int main()  
  19. {  
  20.     int sockClient = socket(AF_INET, SOCK_STREAM, 0);  
  21.   
  22.     struct sockaddr_in addrSrv;  
  23.     addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");  
  24.     addrSrv.sin_family = AF_INET;  
  25.     addrSrv.sin_port = htons(8888);  
  26.     connect(sockClient, ( const struct sockaddr *)&addrSrv, sizeof(struct sockaddr_in));  
  27.   
  28.     char szSendBuf[100] = "this is me";   
  29.     while(1)  
  30.     {  
  31.         send(sockClient, szSendBuf, strlen(szSendBuf) + 1, 0);     
  32.         scanf("%s", szSendBuf);  
  33.     }  
  34.   
  35.     close(sockClient);  
  36.     return 0;  
  37. }  
      makefile代码为:

[plain] view plain copy
  1. all: server client  
  2.   
  3. server: server.o  
  4.     g++ -o server  server.o  
  5.   
  6. client: client.o  
  7.     g++ -o client  client.o  
  8.   
  9. server.o: server.cpp  
  10.     g++ -c server.cpp  
  11.       
  12. client.o:client.cpp  
  13.     g++ -c client.cpp  
  14.   
  15. clean:  
  16.     rm -f server client *.o  
        编译链接后, 先启动服务端, 然后在同一机器上启动三个不同的客户端, 此时,在服务端界面, 结果如下:

[plain] view plain copy
  1. xxxxxx:~/network> ./server  
  2. nfds is 1  
  3. new sock came, fd is 5  
  4. nfds is 1  
  5. recv data [this is me] from fd [5]  
  6. nfds is 1  
  7. new sock came, fd is 6  
  8. nfds is 1  
  9. recv data [this is me] from fd [6]  
  10. nfds is 1  
  11. new sock came, fd is 7  
  12. nfds is 1  
  13. recv data [this is me] from fd [7]  
       

       本文只是epoll的一个简单开始, 比较基础, 后面我们还会进行更多的介绍, 便于深入理解其思路。