织梦CMS - 轻松建站从此开始!

罗索

Linux网络编程一步一步学-epoll同时处理海量连接的代码

jackyhwei 发布于 2011-10-25 22:12 点击:次 
如果这是一个基于epoll的在线服务系统,那么它可以支持9997人同时在线,比如游戏、聊天等。
TAG:

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include <errno.h> 
  4. #include <string.h> 
  5. #include <sys/types.h> 
  6. #include <netinet/in.h> 
  7. #include <sys/socket.h> 
  8. #include <sys/wait.h> 
  9. #include <unistd.h> 
  10. #include <arpa/inet.h> 
  11. #include <openssl/ssl.h> 
  12. #include <openssl/err.h> 
  13. #include <fcntl.h> 
  14. #include <sys/epoll.h> 
  15. #include <sys/time.h> 
  16. #include <sys/resource.h> 
  17.  
  18. #define MAXBUF 1024 
  19. #define MAXEPOLLSIZE 10000 
  20.  
  21. /* 
  22. setnonblocking - 设置句柄为非阻塞方式 
  23. */ 
  24. int setnonblocking(int sockfd) 
  25.     if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) { 
  26.         return -1; 
  27.     } 
  28.     return 0; 
  29.  
  30. /* 
  31. handle_message - 处理每个 socket 上的消息收发 
  32. */ 
  33. int handle_message(int new_fd) 
  34.     char buf[MAXBUF + 1]; 
  35.     int len; 
  36.     /* 开始处理每个新连接上的数据收发 */ 
  37.     bzero(buf, MAXBUF + 1); 
  38.     /* 接收客户端的消息 */ 
  39.     len = recv(new_fd, buf, MAXBUF, 0); 
  40.     if (len > 0) 
  41.         printf 
  42.             ("%d接收消息成功:'%s',共%d个字节的数据/n"
  43.              new_fd, buf, len); 
  44.     else { 
  45.         if (len < 0) 
  46.             printf 
  47.                 ("消息接收失败!错误代码是%d,错误信息是'%s'/n"
  48.                  errno, strerror(errno)); 
  49.         close(new_fd); 
  50.         return -1; 
  51.     } 
  52.     /* 处理每个新连接上的数据收发结束 */ 
  53.     return len; 
  54. /************关于本文档******************************************** 
  55. *filename: epoll-server.c 
  56. *purpose: 演示epoll处理海量socket连接的方法 
  57. *wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com) 
  58. Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言 
  59. *date time:2007-01-31 21:00 
  60. *Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途 
  61. * 但请遵循GPL 
  62. *Thanks to:Google 
  63. *Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力 
  64. * 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献! 
  65. *********************************************************************/ 
  66. int main(int argc, char **argv) 
  67.     int listener, new_fd, kdpfd, nfds, n, ret, curfds; 
  68.     socklen_t len; 
  69.     struct sockaddr_in my_addr, their_addr; 
  70.     unsigned int myport, lisnum; 
  71.     struct epoll_event ev; 
  72.     struct epoll_event events[MAXEPOLLSIZE]; 
  73.     struct rlimit rt; 
  74.  
  75.     if (argv[1]) 
  76.         myport = atoi(argv[1]); 
  77.     else 
  78.         myport = 7838; 
  79.  
  80.     if (argv[2]) 
  81.         lisnum = atoi(argv[2]); 
  82.     else 
  83.         lisnum = 2; 
  84.  
  85.     /* 设置每个进程允许打开的最大文件数 */ 
  86.     rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE; 
  87.     if (setrlimit(RLIMIT_NOFILE, &rt) == -1) { 
  88.         perror("setrlimit"); 
  89.         exit(1); 
  90.     } 
  91.     else printf("设置系统资源参数成功!/n"); 
  92.  
  93.     /* 开启 socket 监听 */ 
  94.     if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 
  95.         perror("socket"); 
  96.         exit(1); 
  97.     } else 
  98.         printf("socket 创建成功!/n"); 
  99.  
  100.     setnonblocking(listener); 
  101.  
  102.     bzero(&my_addr, sizeof(my_addr)); 
  103.     my_addr.sin_family = PF_INET; 
  104.     my_addr.sin_port = htons(myport); 
  105.     if (argv[3]) 
  106.         my_addr.sin_addr.s_addr = inet_addr(argv[3]); 
  107.     else 
  108.         my_addr.sin_addr.s_addr = INADDR_ANY; 
  109.  
  110.     if (bind 
  111.         (listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) 
  112.         == -1) { 
  113.         perror("bind"); 
  114.         exit(1); 
  115.     } else 
  116.         printf("IP 地址和端口绑定成功/n"); 
  117.  
  118.     if (listen(listener, lisnum) == -1) { 
  119.         perror("listen"); 
  120.         exit(1); 
  121.     } else 
  122.         printf("开启服务成功!/n"); 
  123.  
  124.     /* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */ 
  125.     kdpfd = epoll_create(MAXEPOLLSIZE); 
  126.     len = sizeof(struct sockaddr_in); 
  127.     ev.events = EPOLLIN | EPOLLET; 
  128.     ev.data.fd = listener; 
  129.     if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0) { 
  130.         fprintf(stderr, "epoll set insertion error: fd=%d/n", listener); 
  131.         return -1; 
  132.     } else 
  133.         printf("监听 socket 加入 epoll 成功!/n"); 
  134.     curfds = 1; 
  135.     while (1) { 
  136.         /* 等待有事件发生 */ 
  137.         nfds = epoll_wait(kdpfd, events, curfds, -1); 
  138.         if (nfds == -1) { 
  139.             perror("epoll_wait"); 
  140.             break
  141.         } 
  142.         /* 处理所有事件 */ 
  143.         for (n = 0; n < nfds; ++n) { 
  144.             if (events[n].data.fd == listener) { 
  145.                 new_fd = accept(listener, (struct sockaddr *) &their_addr, 
  146.                                 &len); 
  147.                 if (new_fd < 0) { 
  148.                     perror("accept"); 
  149.                     continue
  150.                 } else 
  151.                     printf("有连接来自于: %d:%d, 分配的 socket 为:%d/n"
  152. , inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd); 
  153.  
  154.                 setnonblocking(new_fd); 
  155.                 ev.events = EPOLLIN | EPOLLET; 
  156.                 ev.data.fd = new_fd; 
  157.                 if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, new_fd, &ev) < 0) { 
  158.                     fprintf(stderr, "把 socket '%d' 加入 epoll 失败!%s/n"
  159.                             new_fd, strerror(errno)); 
  160.                     return -1; 
  161.                 } 
  162.                 curfds++; 
  163.             } else { 
  164.                 ret = handle_message(events[n].data.fd); 
  165.                 if (ret < 1 && errno != 11) { 
  166.                     epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd, 
  167.                               &ev); 
  168.                     curfds--; 
  169.                 } 
  170.             } 
  171.         } 
  172.     } 
  173.     close(listener); 
  174.     return 0; 

编译此程序用命令:
gcc -Wall epoll-server.c -o server

运行此程序需要具有管理员权限!

sudo ./server 7838 1

通过测试这一个服务器可能同时处理10000 -3 = 9997 个连接!

如果这是一个在线服务系统,那么它可以支持9997人同时在线,比如游戏、聊天等。

(hwz119)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201110/15197.html]
本文出处:blog.csdn.net/hwz119 作者:hwz119
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容