https://blog.csdn.net/lianghe_work/article/details/46551871

通过epoll实现tcp并发回执服务器(客户端给服务器发啥,服务器就给客户端回啥)

代码如下:

  1. #include <string.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/select.h>
  6. #include <sys/time.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <sys/epoll.h>
  11. #include <errno.h>
  12. #define OPEN_MAX 100
  13. int main(int argc, char *argv[])
  14. {
  15. struct epoll_event event; // 告诉内核要监听什么事件
  16. struct epoll_event wait_event; //内核监听完的结果
  17. //1.创建tcp监听套接字
  18. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  19. //2.绑定sockfd
  20. struct sockaddr_in my_addr;
  21. bzero(&my_addr, sizeof(my_addr));
  22. my_addr.sin_family = AF_INET;
  23. my_addr.sin_port = htons(8001);
  24. my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  25. bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
  26. //3.监听listen
  27. listen(sockfd, 10);
  28. //4.epoll相应参数准备
  29. int fd[OPEN_MAX];
  30. int i = 0, maxi = 0;
  31. memset(fd,-1, sizeof(fd));
  32. fd[0] = sockfd;
  33. int epfd = epoll_create(10); // 创建一个 epoll 的句柄,参数要大于 0, 没有太大意义
  34. if( -1 == epfd ){
  35. perror ("epoll_create");
  36. return -1;
  37. }
  38. event.data.fd = sockfd; //监听套接字
  39. event.events = EPOLLIN; // 表示对应的文件描述符可以读
  40. //5.事件注册函数,将监听套接字描述符 sockfd 加入监听事件
  41. int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);
  42. if(-1 == ret){
  43. perror("epoll_ctl");
  44. return -1;
  45. }
  46. //6.对已连接的客户端的数据处理
  47. while(1)
  48. {
  49. // 监视并等待多个文件(标准输入,udp套接字)描述符的属性变化(是否可读)
  50. // 没有属性变化,这个函数会阻塞,直到有变化才往下执行,这里没有设置超时
  51. ret = epoll_wait(epfd, &wait_event, maxi+1, -1);
  52. //6.1监测sockfd(监听套接字)是否存在连接
  53. if(( sockfd == wait_event.data.fd )
  54. && ( EPOLLIN == wait_event.events & EPOLLIN ) )
  55. {
  56. struct sockaddr_in cli_addr;
  57. int clilen = sizeof(cli_addr);
  58. //6.1.1 从tcp完成连接中提取客户端
  59. int connfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
  60. //6.1.2 将提取到的connfd放入fd数组中,以便下面轮询客户端套接字
  61. for(i=1; i<OPEN_MAX; i++)
  62. {
  63. if(fd[i] < 0)
  64. {
  65. fd[i] = connfd;
  66. event.data.fd = connfd; //监听套接字
  67. event.events = EPOLLIN; // 表示对应的文件描述符可以读
  68. //6.1.3.事件注册函数,将监听套接字描述符 connfd 加入监听事件
  69. ret = epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &event);
  70. if(-1 == ret){
  71. perror("epoll_ctl");
  72. return -1;
  73. }
  74. break;
  75. }
  76. }
  77. //6.1.4 maxi更新
  78. if(i > maxi)
  79. maxi = i;
  80. //6.1.5 如果没有就绪的描述符,就继续epoll监测,否则继续向下看
  81. if(--ret <= 0)
  82. continue;
  83. }
  84. //6.2继续响应就绪的描述符
  85. for(i=1; i<=maxi; i++)
  86. {
  87. if(fd[i] < 0)
  88. continue;
  89. if(( fd[i] == wait_event.data.fd )
  90. && ( EPOLLIN == wait_event.events & (EPOLLIN|EPOLLERR) ))
  91. {
  92. int len = 0;
  93. char buf[128] = "";
  94. //6.2.1接受客户端数据
  95. if((len = recv(fd[i], buf, sizeof(buf), 0)) < 0)
  96. {
  97. if(errno == ECONNRESET)//tcp连接超时、RST
  98. {
  99. close(fd[i]);
  100. fd[i] = -1;
  101. }
  102. else
  103. perror("read error:");
  104. }
  105. else if(len == 0)//客户端关闭连接
  106. {
  107. close(fd[i]);
  108. fd[i] = -1;
  109. }
  110. else//正常接收到服务器的数据
  111. send(fd[i], buf, len, 0);
  112. //6.2.2所有的就绪描述符处理完了,就退出当前的for循环,继续poll监测
  113. if(--ret <= 0)
  114. break;
  115. }
  116. }
  117. }
  118. return 0;
  119. }

运行结果:

源码下载:

Linux网络编程——tcp并发服务器(epoll实现)相关推荐

  1. Linux网络编程——tcp并发服务器(poll实现)

    https://blog.csdn.net/lianghe_work/article/details/46535859 想详细彻底地了解poll或看懂下面的代码请参考<Linux网络编程--I/ ...

  2. Linux网络编程——tcp并发服务器(多进程)

    https://blog.csdn.net/lianghe_work/article/details/46503895 一.tcp并发服务器概述 一个好的服务器,一般都是并发服务器(同一时刻可以响应多 ...

  3. Linux网络编程——tcp并发服务器(多线程)

    https://blog.csdn.net/lianghe_work/article/details/46504243 tcp多线程并发服务器 多线程服务器是对多进程服务器的改进,由于多进程服务器在创 ...

  4. Linux网络编程——tcp并发服务器(I/O复用之select)

    https://blog.csdn.net/lianghe_work/article/details/46519633 与多线程.多进程相比,I/O复用最大的优势是系统开销小,系统不需要建立新的进程或 ...

  5. Linux网络编程——tcp并发服务器(I/O复用之select

    http://blog.csdn.net/lianghe_work/article/details/46519633 与多线程.多进程相比,I/O复用最大的优势是系统开销小,系统不需要建立新的进程或者 ...

  6. 【Linux网络编程】并发服务器的三种实现模型

    服务器设计技术有很多,按使用的协议来分有 TCP 服务器和 UDP 服务器,按处理方式来分有循环服务器和并发服务器. 循环服务器与并发服务器模型 在网络程序里面,一般来说都是许多客户对应一个服务器(多 ...

  7. linux网络编程之并发服务器的三种实现模型 (超级经典)

    转载 : http://blog.csdn.net/tennysonsky/article/details/45671215 服务器设计技术有很多,按使用的协议来分有 TCP 服务器和 UDP 服务器 ...

  8. 【Linux网络编程】并发服务器之select模型

    00. 目录 文章目录 00. 目录 01. 概述 02. I/O复用技术概述 03. select模型服务器实现思路 04. select模型服务器实现 05. 附录 01. 概述 服务器设计技术有 ...

  9. 【Linux网络编程】并发服务器之多线程模型

    00. 目录 文章目录 00. 目录 01. 概述 02. 多线程服务器 03. 多线程服务器实现思路 04. 多线程服务器实现 05. 附录 01. 概述 服务器设计技术有很多,按使用的协议来分有 ...

最新文章

  1. python零基础实例-Python初学零基础也不怕,从0开始!
  2. 我国法定报告的传染病分为几类?包括哪些传染病?
  3. ZCMU 1958: 机器翻译(技巧性的模拟)
  4. 1033 旧键盘打字 (20 分)(c语言)
  5. [转]Java常用概念解答
  6. mysql实现点赞和取消_Redis是如何实现点赞、取消点赞的?
  7. 多智能体强化学习算法【三】【QMIX、MADDPG、MAPPO】
  8. 【转】乱码翻译全攻略
  9. gigabyte计算机主板图解,技嘉主板BIOS如何设置及进入 技嘉主板BIOS设置图解教程(2)...
  10. R语言绘制列线图nomogram分步骤从头到尾实战
  11. 基于MS强度或计数的数据依赖法非标记定量蛋白质组学的蛋白质互作分析(一)
  12. MPS | 聊聊功率因数校正那些事儿
  13. 软件工程方法论对我们经软件开发有多大用处?
  14. 客户体验和营销:您需要了解的 5 个最佳实践
  15. 每天学点统计学——频率和累计频数
  16. 使用husky配置git代码提交规范
  17. 微库:微信互动管理平台
  18. 配水果蜜桔/蜜橘的朋友圈文案,蜜桔/蜜橘水果宣传文案模版
  19. 基于Multisim的4*4 乘法器原理图设计和仿真
  20. Analyzer脑电数据处理步骤

热门文章

  1. 将训练集构建成ImageNet模型
  2. perl exe执行提示缺少文件解决方法
  3. Spring Boot系列教程一:Eclipse安装spring-tool-suite插件
  4. 字符串分割与存入List集合
  5. $Android自定义控件在不同状态下的属性
  6. Standard C++ Episode 7
  7. 小心pthread_cond_signal和SetEvent之间的差异
  8. android git上传出现错误,热更新上传patch包时提示上传失败,文件不合法
  9. jsp 上传转码_最完整的处理jsp处理乱码问题步骤,不需要手工转码
  10. mysql字段唯一确定_验证表里某不确定的字段的值是否唯一的方法?