[cpp] ​​ view plain​​ ​​ copy​​



1、关于字节排序    网际协议采用大端字节序,来传输多字节整数。    系统提供了转换的宏定义,如果主机与网际协议相同,则宏定义为空。

2、客户端    socket -> connect(阻塞,三次握手)-> rcv

3、服务器端    socket -> bind -> listen -> accept(阻塞,三次握手)-> send4、函数介绍    

     a..socket        

          1)函数原型 int socket(int family, int type, int protocol)        

          2)参数:                family: 协议族AF_INET,IPv4协议 ...            type : type 套接字类型SOCK_STREAM 字节流套接字            protocol: IPPROCO_TCP IPPROCO_UDP                     IPPROCO_SCTP       

          3)返回值            成功:返回套接字符            错误:返回INVALID_SOCKET(-1)        

         4)示例


[cpp] ​​ view plain​​ ​​ copy​​



  1. #include <netinet/in.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. int
  5. {  
  6. int
  7. struct
  8.   
  9. if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)  
  10.     {  
  11. return
  12.     }  
  13. }  




        


    b..connect


        1)函数原型 int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)


        2)参数:    


            sockfd: socket 函数返回的套接字描述符


            servaddr : 服务器的IP和端口


            addrlen: 长度(sizeof(servaddr))


        3)返回值


            成功:0


            错误:返回INVALID_SOCKET(-1)


        4)示例


[cpp] ​​ view plain​​ ​​ copy​​



  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <netinet/in.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6.   
  7. int
  8. {  
  9. int
  10. struct
  11.   
  12. if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)  
  13.     {  
  14. "socket error\n");  
  15. return
  16.     }  
  17.   
  18. sizeof(servaddr));  
  19.   
  20. "192.168.0.218");  
  21.     servaddr.sin_family = AF_INET;  
  22.     servaddr.sin_port = htons(55000);  
  23.   
  24. if(connect(socketfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0)  
  25.     {  
  26. "connect error\n");  
  27.     }  
  28.   
  29. return
  30. }  



    c..bind


        1)函数原型 int bind(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)


        2)参数:    


            sockfd: socket 函数返回的套接字描述符


            servaddr : 服务器的IP和端口


            addrlen: 长度(sizeof(servaddr))


        3)返回值


            成功:0


            错误:返回INVALID_SOCKET(-1)


            


    d..listen


        1)函数原型 int listen(int sockfd, int backlog)


        2)参数:    


            sockfd: socket 函数返回的套接字描述符


            backlog : 内核中套接字排队的最大个数


        3)返回值


            成功:0


            错误:返回INVALID_SOCKET


                


    e..accept


        1)函数原型 int accept(int sockfd, const struct sockaddr *servaddr, socklen_t *addrlen)


        2)参数:    


            sockfd: socket 函数返回的套接字描述符




        3)返回值


            servaddr : 客户进程的IP和端口(可设为null)


            addrlen: 长度(sizeof(servaddr))(可设为null)


            成功:从监听套接字返回已连接套接字


            错误:


            如果对客户信息不感兴趣,后两个参数可以置空。


        4)示例


[cpp] ​​ view plain​​ ​​ copy​​



  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <netinet/in.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6.   
  7. int
  8. {  
  9. int
  10. int
  11. int
  12. struct
  13. struct
  14. char
  15.   
  16. "accept started\n");  
  17.   
  18. //socket    
  19. if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)  
  20.     {  
  21. "socket error\n");  
  22. return
  23.     }  
  24.   
  25. sizeof(servaddr));  
  26.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  27.     servaddr.sin_family = AF_INET;  
  28.     servaddr.sin_port = htons(59000);  
  29.   
  30. //bind
  31. if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)  
  32.     {  
  33. "bind error\n");  
  34. //return -1;
  35.     }  
  36.   
  37. //listen
  38.     listen(listenfd, 5);  
  39.   
  40. //accept
  41.     socketfd = accept(listenfd, NULL, NULL);  
  42.   
  43.   
  44.   
  45. while(1)  
  46.     {  
  47. "start receive %d...\n", count++);  
  48. sizeof(readbuf), 0);  
  49.   
  50.         nread = recv(socketfd, readbuf, 10, 0);  
  51. if(nread>0)  
  52.         {  
  53. '\0';  
  54. "receiveed %s, nread = %d\n\n", readbuf, nread);  
  55.         }  
  56.     }  
  57.   
  58. return
  59. }  



    /**************************************************************


    从 I/O 事件分派机制来看,使用 select()是不合适的,因为它所支持的并发连接数有限(通


    常在 1024 个以内)。如果考虑性能,poll()也是不合适的,尽管它可以支持的较高的 TCP 并发


    数,但是由于其采用“轮询”机制,当并发数较高时,其运行效率相当低,并可能存在 I/O 事


    件分派不均,导致部分 TCP 连接上的 I/O 出现“饥饿”现象。而如果使用 epoll 或 AIO,则没


    有上述问题(早期 Linux 内核的 AIO 技术实现是通过在内核中为每个 I/O 请求创建一个线程来


    实现的,这种实现机制在高并发 TCP 连接的情形下使用其实也有严重的性能问题。但在最新的


    Linux 内核中,AIO 的实现已经得到改进)。


    支持一个进程打开大数目的 socket 描述符(FD)select 最不能忍受的是一个进程所打开的


    FD 是有一定限制的,由 FD_SETSIZE 设置,默认值是 2048。对于那些需要支持的上万连接数目


    的 IM 服务器来说显然太少了。


    这时候你一是可以选择修改这个宏然后重新编译内核,不过资料


    也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache 方


    案),不过虽然 linux 上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步


    远比不上线程间同步的高效,所以也不是一种完美的方案。不过 epoll 则没有这个限制,它所


    支持的 FD 上限是最大可以打开文件的数目,这个数字一般远大于 2048,举个例子,在 1GB 内存


    的机器上大约是 10 万左右,具体数目可以 cat /proc/sys/fs/file-max 察看,一般来说这个数


    目和系统内存关系很大。


    ******************************************************************/        


5. select函数


    1)函数原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);


    2)参数:    


        sockfd: socket 函数返回的套接字描述符


        readfds : 读描述符集合


        writefds: 写描述符集合


        errorfds: 错误描述符集合


        timeout:  超时


    3)返回值


        成功:返回值 0:无 >0:描述符就绪的总位数


        错误:返回INVALID_SOCKET(-1)


    4)包含头文件: include <sys/select.h> include <sys/time.h>


    5)示例


[cpp] ​​ view plain​​ ​​ copy​​



  1. /* 实现功能:通过select处理多个socket
  2.  * 监听一个端口,监听到有链接时,添加到select的w.
  3.  */
  4. #include "select.h"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <sys/socket.h>
  8. #include <sys/select.h>
  9. #include <sys/time.h>
  10. #include <netinet/in.h>
  11.   
  12. typedef struct
  13. int
  14. struct sockaddr_in addr; /* client's address information */
  15. } CLIENT;  
  16.   
  17. #define MYPORT 59000
  18.   
  19. //最多处理的connect
  20. #define BACKLOG 5
  21.   
  22. //最多处理的connect
  23. CLIENT client[BACKLOG];  
  24.   
  25. //当前的连接数
  26. int
  27.   
  28. //数据接受 buf
  29. #define REVLEN 10
  30. char
  31. //显示当前的connection
  32. void
  33.   
  34. int
  35. {  
  36. int
  37. int
  38.     fd_set readfds, writefds;  
  39. int
  40. struct
  41. struct
  42. struct
  43.   
  44. for(i=0; i<BACKLOG; i++)  
  45.     {  
  46.         client[i].fd = -1;  
  47.     }  
  48.   
  49. //socket
  50. if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)  
  51.     {  
  52. "socket error\n");  
  53. return
  54.     }  
  55.   
  56. sizeof(server_addr));  
  57.     server_addr.sin_family  =  AF_INET;  
  58.     server_addr.sin_port = htons(MYPORT);  
  59.     server_addr.sin_addr.s_addr  =  htonl(INADDR_ANY);   
  60.   
  61. //bind
  62. if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)  
  63.     {  
  64. "bind error\n");  
  65. return
  66.     }  
  67.   
  68. //listen
  69. if(listen(sockListen, 5) < 0)  
  70.     {  
  71. "listen error\n");  
  72. return
  73.     }  
  74.   
  75. for(i=0; i<BACKLOG; i++)  
  76.     {  
  77.         client[i].fd = -1;  
  78.     }  
  79.   
  80. //select
  81. while(1)  
  82.     {  
  83.         FD_ZERO(&readfds);  
  84.         FD_SET(sockListen, &readfds);  
  85.         sockMax = sockListen;  
  86.       
  87. //加入client
  88. for(i=0; i<BACKLOG; i++)  
  89.         {  
  90. if(client[i].fd >0)  
  91.             {  
  92.                 FD_SET(client[i].fd, &readfds);  
  93. if(sockMax<client[i].fd)   
  94.                     sockMax = client[i].fd;  
  95.             }  
  96.         }  
  97.           
  98.         timeout.tv_sec=3;                  
  99.         timeout.tv_usec=0;  
  100. //select
  101. int)sockMax+1, &readfds, NULL, NULL, &timeout);  
  102. if(ret < 0)  
  103.         {  
  104. "select error\n");  
  105. break;  
  106.         }  
  107. else if(ret == 0)  
  108.         {  
  109. "timeout ...\n");  
  110. continue;  
  111.         }  
  112. "test111\n");  
  113.       
  114. //读取数据
  115. for(i=0; i<BACKLOG; i++)  
  116.         {  
  117. if(client[i].fd>0 && FD_ISSET(client[i].fd, &readfds))  
  118.             {  
  119. if(recvLen != REVLEN)  
  120.                 {  
  121. while(1)  
  122.                     {  
  123. //recv数据
  124. char
  125. if(ret == 0)  
  126.                         {  
  127.                             client[i].fd = -1;  
  128.                             recvLen = 0;  
  129. break;  
  130.                         }  
  131. else if(ret < 0)  
  132.                         {  
  133.                             client[i].fd = -1;  
  134.                             recvLen = 0;  
  135. break;  
  136.                         }  
  137. //数据接受正常
  138.                         recvLen = recvLen+ret;  
  139. if(recvLen<REVLEN)  
  140.                         {  
  141. continue;  
  142.                         }  
  143. else
  144.                         {  
  145. //数据接受完毕
  146. "%s, buf = %s\n", inet_ntoa(client[i].addr.sin_addr) , recvBuf);  
  147. //close(client[i].fd);
  148. //client[i].fd = -1;
  149.                             recvLen = 0;  
  150. break;  
  151.                         }  
  152.                     }  
  153.                 }  
  154.             }  
  155.         }  
  156.       
  157. //如果可读
  158. if(FD_ISSET(sockListen, &readfds))  
  159.         {  
  160. "isset\n");  
  161. //(struct sockaddr*)&client_addr
  162.           
  163. if(sockSvr == -1)  
  164.             {  
  165. "accpet error\n");  
  166.             }  
  167. else
  168.             {  
  169.                 currentClient++;  
  170.             }  
  171.           
  172. for(i=0; i<BACKLOG; i++)  
  173.             {  
  174. if(client[i].fd < 0)  
  175.                 {  
  176.                     client[i].fd = sockSvr;  
  177.                     client[i].addr = client_addr;  
  178. "You got a connection from %s \n",inet_ntoa(client[i].addr.sin_addr) );  
  179. break;  
  180.                 }  
  181.             }  
  182. //close(sockListen);
  183.         }  
  184.     }  
  185.   
  186. "test\n");  
  187. return
  188. }  
  189.   
  190. //显示当前的connection
  191. void
  192. {  
  193. int
  194. "client count = %d\n", currentClient);  
  195.   
  196. for(i=0; i<BACKLOG; i++)  
  197.     {  
  198. "[%d] = %d", i, client[i].fd);  
  199.     }  
  200. "\n");  
  201. }  



6. poll函数


    1)函数原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);


    2)参数:    


        sockfd: socket 函数返回的套接字描述符


        readfds : 读描述符集合


        writefds: 写描述符集合


        errorfds: 错误描述符集合


        timeout:  超时


    3)返回值


        成功:返回值 0:无 >0:描述符就绪的总位数


        错误:返回INVALID_SOCKET(-1)


    4)包含头文件: include <sys/select.h> include <sys/time.h>


    5) 示例


[cpp] ​​ view plain​​ ​​ copy​​



  1. /* 实现功能:通过poll, 处理多个socket
  2.  * 监听一个端口,监听到有链接时,添加到poll.
  3.  */
  4. #include "select.h"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/socket.h>
  9. #include <poll.h>
  10. #include <sys/time.h>
  11. #include <netinet/in.h>
  12.   
  13. typedef struct
  14. int
  15. struct sockaddr_in addr; /* client's address information */
  16. } CLIENT;  
  17.   
  18. #define MYPORT 59000
  19.   
  20. //最多处理的connect
  21. #define BACKLOG 5
  22.   
  23. //当前的连接数
  24. int
  25.   
  26. //数据接受 buf
  27. #define REVLEN 10
  28. char
  29.   
  30. #define OPEN_MAX 1024
  31.   
  32. int
  33. {  
  34. int
  35. int
  36.     fd_set readfds, writefds;  
  37. int
  38. int
  39. struct
  40. struct
  41.   
  42. struct
  43.   
  44.   
  45. //socket
  46. if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)  
  47.     {  
  48. "socket error\n");  
  49. return
  50.     }  
  51.   
  52. sizeof(server_addr));  
  53.     server_addr.sin_family  =  AF_INET;  
  54.     server_addr.sin_port = htons(MYPORT);  
  55.     server_addr.sin_addr.s_addr  =  htonl(INADDR_ANY);   
  56.   
  57. //bind
  58. if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)  
  59.     {  
  60. "bind error\n");  
  61. return
  62.     }  
  63.   
  64. //listen
  65. if(listen(sockListen, 5) < 0)  
  66.     {  
  67. "listen error\n");  
  68. return
  69.     }  
  70.   
  71.   
  72. //clientfd 初始化
  73.     clientfd[0].fd = sockListen;  
  74. //POLLRDNORM;
  75.     sockMax = 0;  
  76. for(i=1; i<OPEN_MAX; i++)  
  77.     {  
  78.         clientfd[i].fd = -1;  
  79.     }  
  80.   
  81. //select
  82. while(1)  
  83.     {  
  84.         timeout=3000;                  
  85. //select
  86.         ret = poll(clientfd, sockMax+1, timeout);  
  87.       
  88. if(ret < 0)  
  89.         {  
  90. "select error\n");  
  91. break;  
  92.         }  
  93. else if(ret == 0)  
  94.         {  
  95. "timeout ...\n");  
  96. continue;  
  97.         }  
  98.       
  99. if (clientfd[0].revents & POLLIN)//POLLRDNORM
  100.         {  
  101. //(struct sockaddr*)&client_addr
  102.           
  103. if(sockSvr == -1)  
  104.             {  
  105. "accpet error\n");  
  106.             }  
  107. else
  108.             {  
  109.                 currentClient++;  
  110.             }  
  111.           
  112. for(i=0; i<OPEN_MAX; i++)  
  113.             {  
  114. if(clientfd[i].fd<0)  
  115.                 {  
  116.                     clientfd[i].fd = sockSvr;  
  117. break;  
  118.                 }  
  119.             }  
  120. if(i==OPEN_MAX)  
  121.             {  
  122. "too many connects\n");  
  123. return
  124.             }  
  125. //POLLRDNORM;
  126. if(i>sockMax)  
  127.                 sockMax = i;  
  128.         }  
  129.       
  130. //读取数据
  131. for(i=1; i<=sockMax; i++)  
  132.         {  
  133. if(clientfd[i].fd < 0)  
  134. continue;  
  135.           
  136. if (clientfd[i].revents & (POLLIN | POLLERR))//POLLRDNORM
  137.             {  
  138. if(recvLen != REVLEN)  
  139.                 {  
  140. while(1)  
  141.                     {  
  142. //recv数据
  143. char
  144. if(ret == 0)  
  145.                         {  
  146.                             clientfd[i].fd = -1;  
  147.                             recvLen = 0;  
  148. break;  
  149.                         }  
  150. else if(ret < 0)  
  151.                         {  
  152.                             clientfd[i].fd = -1;  
  153.                             recvLen = 0;  
  154. break;  
  155.                         }  
  156. //数据接受正常
  157.                         recvLen = recvLen+ret;  
  158. if(recvLen<REVLEN)  
  159.                         {  
  160. continue;  
  161.                         }  
  162. else
  163.                         {  
  164. //数据接受完毕
  165. "buf = %s\n",  recvBuf);  
  166. //close(client[i].fd);
  167. //client[i].fd = -1;
  168.                             recvLen = 0;  
  169. break;  
  170.                         }  
  171.                     }  
  172.                 }  
  173.             }  
  174.         }  
  175.     }  
  176.   
  177. return
  178. }  



6. epoll函数


        2. 常用模型的缺点


        如果不摆出来其他模型的缺点,怎么能对比出 Epoll 的优点呢。


        2.1 PPC/TPC 模型


        这两种模型思想类似,就是让每一个到来的连接一边自己做事去,别再来烦我 。只是 PPC 是为它开了一个进程,而 TPC 开了一个线程。可是别烦我是有代价的,它要时间和空间啊,连接多了之后,那么多的进程 / 线程切换,这开销就上来了;因此这类模型能接受的最大连接数都不会高,一般在几百个左右。


        2.2 select 模型


        1. 最大并发数限制,因为一个进程所打开的 FD (文件描述符)是有限制的,由 FD_SETSIZE 设置,默认值是 1024/2048 ,因此 Select 模型的最大并发数就被相应限制了。自己改改这个 FD_SETSIZE ?想法虽好,可是先看看下面吧 …


        2. 效率问题, select 每次调用都会线性扫描全部的 FD 集合,这样效率就会呈现线性下降,把 FD_SETSIZE 改大的后果就是,大家都慢慢来,什么?都超时了??!!


        3. 内核 / 用户空间 内存拷贝问题,如何让内核把 FD 消息通知给用户空间呢?在这个问题上 select 采取了内存拷贝方法。


        2.3 poll 模型


        基本上效率和 select 是相同的, select 缺点的 2 和 3 它都没有改掉。


        3. Epoll 的提升


        把其他模型逐个批判了一下,再来看看 Epoll 的改进之处吧,其实把 select 的缺点反过来那就是 Epoll 的优点了。


        3.1. Epoll 没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于 2048, 一般来说这个数目和系统内存关系很大 ,具体数目可以 cat /proc/sys/fs/file-max 察看。


        3.2. 效率提升, Epoll 最大的优点就在于它只管你“活跃”的连接 ,而跟连接总数无关,因此在实际的网络环境中, Epoll 的效率就会远远高于 select 和 poll 。


        3.3. 内存拷贝, Epoll 在这点上使用了“共享内存 ”,这个内存拷贝也省略了。


         


        4. Epoll 为什么高效


        Epoll 的高效和其数据结构的设计是密不可分的,这个下面就会提到。


        首先回忆一下 select 模型,当有 I/O 事件到来时, select 通知应用程序有事件到了快去处理,而应用程序必须轮询所有的 FD 集合,测试每个 FD 是否有事件发生,并处理事件;代码像下面这样:




        int res = select(maxfd+1, &readfds, NULL, NULL, 120);


        if (res > 0)


        {


            for (int i = 0; i < MAX_CONNECTION; i++)


            {


                if (FD_ISSET(allConnection[i], &readfds))


                {


                    handleEvent(allConnection[i]);


                }


            }


        }


        // if(res == 0) handle timeout, res < 0 handle error


         


        Epoll 不仅会告诉应用程序有I/0 事件到来,还会告诉应用程序相关的信息,这些信息是应用程序填充的,因此根据这些信息应用程序就能直接定位到事件,而不必遍历整个FD 集合。


        int res = epoll_wait(epfd, events, 20, 120);


        for (int i = 0; i < res;i++)


        {


            handleEvent(events[n]);


        }


        5. Epoll 关键数据结构


        前面提到 Epoll 速度快和其数据结构密不可分,其关键数据结构就是:


        struct epoll_event {


            __uint32_t events;      // Epoll events


            epoll_data_t data;      // User data variable


        };


        typedef union epoll_data {


            void *ptr;


            int fd;


            __uint32_t u32;


            __uint64_t u64;


        } epoll_data_t;


        


        可见 epoll_data 是一个 union 结构体 , 借助于它应用程序可以保存很多类型的信息 :fd 、指针等等。有了它,应用程序就可以直接定位目标了。


        6. 使用 Epoll


        既然 Epoll 相比 select 这么好,那么用起来如何呢?会不会很繁琐啊 … 先看看下面的三个函数吧,就知道 Epoll 的易用了。


         


        int epoll_create(int size);


        生成一个 Epoll 专用的文件描述符,其实是申请一个内核空间,用来存放你想关注的 socket fd 上是否发生以及发生了什么事件。 size 就是你在这个 Epoll fd 上能关注的最大 socket fd 数,大小自定,只要内存足够。


        


        int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event );


        控制某个 Epoll 文件描述符上的事件:注册、修改、删除。其中参数 epfd 是 epoll_create() 创建 Epoll 专用的文件描述符。相对于 select 模型中的 FD_SET 和 FD_CLR 宏。


        op:EPOLL_CTL_ADD


                 Register the target file descriptor fd on the epoll instance 


              EPOLL_CTL_MOD


                  Change the event event associated with the target file descriptor fd.


              EPOLL_CTL_DEL


                   Remove  (deregister)  the  target  file descriptor fd from the epoll instance




        


        int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);


        等待 I/O 事件的发生;参数说明:


        epfd: 由 epoll_create() 生成的 Epoll 专用的文件描述符;


        epoll_event: 用于回传代处理事件的数组;


        maxevents: 每次能处理的事件数;


        timeout: 等待 I/O 事件发生的超时值,单位 ms


        返回发生事件数。


        相对于 select 模型中的 select 函数。


        


[cpp] ​​ view plain​​ ​​ copy​​



  1. /* 实现功能:通过epoll, 处理多个socket
  2.  * 监听一个端口,监听到有链接时,添加到epoll_event
  3.  */
  4. #include "select.h"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/socket.h>
  9. #include <poll.h>
  10. #include <sys/epoll.h>
  11. #include <sys/time.h>
  12. #include <netinet/in.h>
  13.   
  14. typedef struct
  15. int
  16. struct sockaddr_in addr; /* client's address information */
  17. } CLIENT;  
  18.   
  19. #define MYPORT 59000
  20.   
  21. //最多处理的connect
  22. #define MAX_EVENTS 500
  23.   
  24. //当前的连接数
  25. int
  26.   
  27. //数据接受 buf
  28. #define REVLEN 10
  29. char
  30.   
  31. //EPOLL相关 
  32. //epoll描述符
  33. int
  34. //事件数组
  35. struct
  36.   
  37. void AcceptConn(int
  38. void RecvData(int
  39.   
  40. int
  41. {  
  42. int
  43. int
  44.     fd_set readfds, writefds;  
  45. int
  46. int
  47. struct
  48. struct
  49.       
  50. //socket
  51. if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)  
  52.     {  
  53. "socket error\n");  
  54. return
  55.     }  
  56.       
  57. sizeof(server_addr));  
  58.     server_addr.sin_family  =  AF_INET;  
  59.     server_addr.sin_port = htons(MYPORT);  
  60.     server_addr.sin_addr.s_addr  =  htonl(INADDR_ANY);   
  61.       
  62. //bind
  63. if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)  
  64.     {  
  65. "bind error\n");  
  66. return
  67.     }  
  68.       
  69. //listen
  70. if(listen(sockListen, 5) < 0)  
  71.     {  
  72. "listen error\n");  
  73. return
  74.     }  
  75.       
  76. //1. epoll 初始化
  77.     epollfd = epoll_create(MAX_EVENTS);  
  78. struct
  79.     event.events = EPOLLIN|EPOLLET;  
  80.     event.data.fd = sockListen;  
  81.       
  82. //2. epoll_ctrl
  83. if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sockListen, &event) < 0)  
  84.     {  
  85. "epoll add fail : fd = %d\n", sockListen);  
  86. return
  87.     }  
  88.       
  89. //epoll
  90. while(1)  
  91.     {  
  92.         timeout=3000;                  
  93. //3. epoll_wait
  94. int
  95.           
  96. if(ret < 0)  
  97.         {  
  98. "epoll error\n");  
  99. break;  
  100.         }  
  101. else if(ret == 0)  
  102.         {  
  103. "timeout ...\n");  
  104. continue;  
  105.         }  
  106.           
  107. //直接获取了事件数量,给出了活动的流,这里是和poll区别的关键
  108. int
  109. for(n=0; n<ret; n++)  
  110.         {  
  111. //错误退出
  112. if
  113.                 (eventList[n].events & EPOLLHUP) ||  
  114.                 !(eventList[n].events & EPOLLIN))  
  115.             {  
  116. "epoll error\n");  
  117.               close (eventList[n].data.fd);  
  118. return
  119.             }  
  120.               
  121. if
  122.             {  
  123.                 AcceptConn(sockListen);  
  124.           
  125. else{  
  126.                 RecvData(eventList[n].data.fd);  
  127. //不删除
  128. //   epoll_ctl(epollfd, EPOLL_CTL_DEL, pEvent->data.fd, pEvent);
  129.             }  
  130.         }  
  131.     }  
  132.       
  133.     close(epollfd);  
  134.     close(sockListen);  
  135.       
  136. "test\n");  
  137. return
  138. }  
  139.   
  140. /**************************************************
  141. 函数名:AcceptConn
  142. 功能:接受客户端的链接
  143. 参数:srvfd:监听SOCKET
  144. ***************************************************/
  145. void AcceptConn(int
  146. {  
  147. struct
  148. sizeof(struct
  149.     bzero(&sin, len);  
  150.   
  151. int confd = accept(srvfd, (struct
  152.   
  153. if
  154.     {  
  155. "bad accept\n");  
  156. return;  
  157. else
  158.     {  
  159. "Accept Connection: %d", confd);  
  160.     }  
  161.   
  162. //setnonblocking(confd);
  163.   
  164. //4. epoll_wait
  165. //将新建立的连接添加到EPOLL的监听中
  166. struct
  167.     event.data.fd = confd;  
  168.     event.events =  EPOLLIN|EPOLLET;  
  169.     epoll_ctl(epollfd, EPOLL_CTL_ADD, confd, &event);  
  170. }  
  171.   
  172. //读取数据
  173. void RecvData(int
  174. {  
  175. int
  176. int
  177.       
  178.     memset(recvBuf, 0, REVLEN);  
  179. "RecvData function\n");  
  180.       
  181. if(recvLen != REVLEN)  
  182.     {  
  183. while(1)  
  184.         {  
  185. //recv数据
  186. char
  187. if(ret == 0)  
  188.             {  
  189.                 recvLen = 0;  
  190. break;  
  191.             }  
  192. else if(ret < 0)  
  193.             {  
  194.                 recvLen = 0;  
  195. break;  
  196.             }  
  197. //数据接受正常
  198.             recvLen = recvLen+ret;  
  199. if(recvLen<REVLEN)  
  200.             {  
  201. continue;  
  202.             }  
  203. else
  204.             {  
  205. //数据接受完毕
  206. "buf = %s\n",  recvBuf);  
  207.                 recvLen = 0;  
  208. break;  
  209.             }  
  210.         }  
  211.     }  
  212.   
  213. "content is %s", recvBuf);