上一篇博客用多线程实现服务端和多个客户端的通信,但是在实际应用中如果服务端有高并发的需求,多线程并不是一个好选择。

实现高并发的一种方法是IO多路复用,也就是select,poll,epoll等等。

于是我采用epoll再修改了服务端,实现单线程服务多个客户端。

服务端:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <fcntl.h> // open function
  4 #include <unistd.h> // close function
  5 #include <sys/socket.h>
  6 #include <netinet/in.h>
  7 #include <string.h>
  8 #include <pthread.h>
  9 #include <errno.h>
 10 #include <sys/epoll.h>
 11
 12 const int PORT = 8888;
 13 /*
 14     listen_loop(): epoll监听套接字,作不同处理
 15     accept_conn(): 新的客户端连接进来,执行accept,将fd加入epoll set
 16     recv_message(): recv并且重复输出一份给客户端
 17  */
 18 void listen_loop();
 19 void accept_conn(unsigned int sock_fd, unsigned int epollfd);
 20 void recv_message(unsigned int sock_fd);
 21
 22 int main(void) {
 23     int sock_fd;
 24     struct sockaddr_in server_addr;
 25
 26     //初始化socket
 27     sock_fd = socket(AF_INET, SOCK_STREAM, 0);
 28     if (sock_fd < 0) {
 29         perror("socket:");
 30         return 0;
 31     }
 32
 33     //编辑地址
 34     memset(&server_addr, 0, sizeof(server_addr));
 35     server_addr.sin_family = AF_INET;//ipv_4
 36     server_addr.sin_port = htons(PORT);//监听端口8888
 37     server_addr.sin_addr.s_addr = INADDR_ANY;//本地的任意地址
 38
 39     //绑定然后监听
 40     if (bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
 41         perror("bind:");
 42         return 0;
 43     }
 44     if (listen(sock_fd, 10) < 0) {
 45         perror("listen");
 46         return 0;
 47     }
 48
 49     listen_loop(sock_fd);
 50
 51     return 0;
 52 }
 53 void accept_conn(unsigned int sock_fd, unsigned int epollfd) {
 54     struct sockaddr_in clientaddr;
 55     struct epoll_event event;
 56     socklen_t len = sizeof(struct sockaddr);
 57     int accept_fd = 0;
 58
 59     accept_fd = accept(sock_fd, (struct sockaddr*)&clientaddr, &len);
 60
 61     if (accept_fd <= 0) {
 62         perror("accept error");
 63         return;
 64     }
 65
 66     //将新建连接加入epoll set
 67     event.data.fd = accept_fd;
 68     event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
 69     epoll_ctl(epollfd, EPOLL_CTL_ADD, accept_fd, &event);
 70     return;
 71 }
 72
 73 void recv_message(unsigned int sock_fd) {
 74     char recv_buf[1024], send_buf[1024];
 75
 76     memset(recv_buf, 0, sizeof(recv_buf));
 77     memset(send_buf, 0, sizeof(send_buf));
 78
 79     recv(sock_fd, recv_buf, sizeof(recv_buf), 0);
 80     fputs(recv_buf, stdout);
 81     strcpy(send_buf, recv_buf);
 82     send(sock_fd, send_buf, sizeof(send_buf), 0);
 83
 84     return;
 85 }
 86 void listen_loop(unsigned int sock_fd)
 87 {
 88     int epollfd, i, ret;
 89     int timeout = 300;
 90     struct epoll_event event;
 91     struct epoll_event eventList[10];
 92
 93     /*创建epoll监听事件*/
 94     epollfd = epoll_create(10);
 95     event.events = EPOLLIN | EPOLLET;
 96     event.data.fd = sock_fd;
 97
 98     /*注册epoll监听事件.*/
 99     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock_fd, &event) < 0) {
100         printf("register epoll event err !");
101         return;
102     }
103
104     while (1) {
105         ret = epoll_wait(epollfd, eventList, 10, timeout);
106
107         /*epoll事件错误.*/
108         if (ret < 0) {
109             printf("epoll event err!");
110             break;
111         }
112         /*无事件返回.*/
113         else if (ret == 0) {
114             continue;
115         }
116
117         /*epoll返回事件.*/
118         for (i = 0; i < ret; i++) {
119             /*epoll 错误*/
120             if ((eventList[i].events & EPOLLERR) || (eventList[i].events & EPOLLHUP) || !(eventList[i].events & EPOLLIN)) {
121                 printf("epoll error\n");
122                 close(eventList[i].data.fd);
123                 exit(-1);
124             }
125
126             //half connection
127             if (eventList[i].events & EPOLLRDHUP) {
128                 printf("//one client close the conne.//\n");
129                 close(eventList[i].data.fd);
130             }
131
132             /*accept事件*/
133             if (eventList[i].data.fd == sock_fd) {
134                 accept_conn(sock_fd, epollfd);
135             }
136             /*非sock_fd则为其他事件.*/
137             else {
138                 recv_message(eventList[i].data.fd);
139             }
140         }
141     }
142     close(epollfd);
143     close(sock_fd);
144     return;
145 }

转载于:https://www.cnblogs.com/liangf27/p/9366348.html

Linux下socket通信和epoll相关推荐

  1. linux下socket编程和epoll的使用

      这两天在学Linux下的网络编程,于是便看了些关于socket和epoll的资料.   首先介绍socket,socket编程我之前也接触过,不过是在windows下接触的.和windows不同的 ...

  2. Linux 下socket通信终极指南(附TCP、UDP完整代码)

    linux下用socket通信,有TCP.UDP两种协议,网上的很多教程把两个混在了一起,或者只讲其中一种.现在我把自己这两天研究的成果汇总下来,写了一个完整的,适合初学者参考,也方便自己以后查阅. ...

  3. Linux下Socket通信中非阻塞connect、select、recv 和 recvfrom、send和sendto大致讲解,附带非租塞connect代码、MSG_NOSIGNAL

    linux中send函数MSG_NOSIGNAL异常消息 在服务器端用ctrl+c 来结束服务器接收进程来模拟服务器宕机的情况,结束服务 socket 进程之后,服务端自然关闭进程,可是 client ...

  4. linux socket ip层配置,Linux下Socket通信(TCP实现)

    近期在做的项目中,涉及到了进程间数据传输,系统的原本实现是通过管道,但是原有的实现中两个进程是在同一台机器,而且两个进程的关系为父子关系,而我们要做的是将其中一个进程移植到服务器上,因此两个进程要分开 ...

  5. linux下socket通信,server和client简单例子

    #include "metafile.h" #include <string.h> #include <ctype.h>//定义全局变量 TrackerLi ...

  6. 【Linux】一篇文章搞定 CPP模拟实现TCP协议下socket通信

    CPP模拟实现TCP协议下socket通信 1. TCP 编程流程图 2. 数据收发阶段使用的API 2.1 send接口 2.2 recv接口 3. 两个队列 4. 总结TCP 编程双端流程 5. ...

  7. linux下TCP通信简单实例

    linux下TCP通信简单实例 基于TCP(面向连接)的socket编程,分为服务器端和客户端 服务器端的流程如下: (1)创建套接字(socket) (2)将套接字绑定到一个本地地址和端口上(bin ...

  8. Linux下进程通信的八种方法

    Linux下进程通信的八种方法:管道(pipe),命名管道(FIFO),内存映射(mapped memeory),消息队列(message queue),共享内存(shared memory),信号量 ...

  9. 【流媒体服务器Mediasoup】 NodeJs与C++信令通信详解及Linux下管道通信的详解(五)

    目录 前言 匿名管道进程间通信 进程间管道 的创建与图解 MediaSoup中的管道创建 MediaSoup Channel的创建 NodeJs和 C++ 管道通信的过程 MediaSoup 消息确认 ...

最新文章

  1. Linux系统JDK安装和配置
  2. xcode 中无法进行虚拟机调试_在软件部署中使用 strace 进行调试
  3. 字符串排序 java_java字符串排序
  4. TJA1050只能RX不能TX
  5. 盘点Kubernetes网络问题的4种解决方案
  6. 约束条件创建定义表(主码,外码的确定和防止空值等)
  7. 打造云上金融!网易云信入选「2021 数字化转型最佳案例 Top10」
  8. 张正友标定法 【计算机视觉学习笔记--双目视觉几何框架系列】
  9. 如何实现两列等高效果?
  10. 【flink】Flink 1.12.2 源码浅析 : yarn-per-job模式解析 JobMasger启动 YarnJobClusterEntrypoint
  11. paddlepaddle的使用
  12. Spark-SQL教程
  13. Ruby在Windows下安装
  14. Common Digester学习
  15. Unix时间和leap seconds(闰秒)简要分析
  16. 听北大公开课庄明科老师《大学生职业素养提升》第一集:《自我效能感》的笔记
  17. 怎样做一个更有价值的人
  18. Oracle学习——第四讲(增删改查)
  19. mysql 查看slave状态_解读show slave status 命令判断MySQL复制同步状态
  20. 用uni-app开发的微信小程序轮播图----和用微信小程序原生开发的轮播图

热门文章

  1. GoldenGate组态(四)它veridata组态
  2. 微信开发博客——柳峰
  3. 记一次CurrentDirectory导致的问题
  4. MapReduce算法设计(三)----相对频率计算
  5. COM组件设计与应用(三)(转载)
  6. 联邦知识蒸馏概述与思考(续)
  7. Centerface:开源实用的边缘设备无锚人脸检测与对齐算法
  8. StegaStamp:加州大学伯克利分校开源神奇的照片隐写术,打印的照片能当二维码用...
  9. 未来2年,会Python的人将会非常抢手
  10. matlab中ga函数用法,matlab遗传算法ga函数