Linux下socket通信和epoll
上一篇博客用多线程实现服务端和多个客户端的通信,但是在实际应用中如果服务端有高并发的需求,多线程并不是一个好选择。
实现高并发的一种方法是IO多路复用,也就是select,poll,epoll等等。
于是我采用epoll再修改了服务端,实现单线程服务多个客户端。
服务端:
- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h> // open function
- #include <unistd.h> // close function
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <string.h>
- #include <pthread.h>
- #include <errno.h>
- #include <sys/epoll.h>
- const int PORT = ;
- /*
- listen_loop(): epoll监听套接字,作不同处理
- accept_conn(): 新的客户端连接进来,执行accept,将fd加入epoll set
- recv_message(): recv并且重复输出一份给客户端
- */
- void listen_loop();
- void accept_conn(unsigned int sock_fd, unsigned int epollfd);
- void recv_message(unsigned int sock_fd);
- int main(void) {
- int sock_fd;
- struct sockaddr_in server_addr;
- //初始化socket
- sock_fd = socket(AF_INET, SOCK_STREAM, );
- if (sock_fd < ) {
- perror("socket:");
- return ;
- }
- //编辑地址
- memset(&server_addr, , sizeof(server_addr));
- server_addr.sin_family = AF_INET;//ipv_4
- server_addr.sin_port = htons(PORT);//监听端口8888
- server_addr.sin_addr.s_addr = INADDR_ANY;//本地的任意地址
- //绑定然后监听
- if (bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < ) {
- perror("bind:");
- return ;
- }
- if (listen(sock_fd, ) < ) {
- perror("listen");
- return ;
- }
- listen_loop(sock_fd);
- return ;
- }
- void accept_conn(unsigned int sock_fd, unsigned int epollfd) {
- struct sockaddr_in clientaddr;
- struct epoll_event event;
- socklen_t len = sizeof(struct sockaddr);
- int accept_fd = ;
- accept_fd = accept(sock_fd, (struct sockaddr*)&clientaddr, &len);
- if (accept_fd <= ) {
- perror("accept error");
- return;
- }
- //将新建连接加入epoll set
- event.data.fd = accept_fd;
- event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
- epoll_ctl(epollfd, EPOLL_CTL_ADD, accept_fd, &event);
- return;
- }
- void recv_message(unsigned int sock_fd) {
- char recv_buf[], send_buf[];
- memset(recv_buf, , sizeof(recv_buf));
- memset(send_buf, , sizeof(send_buf));
- recv(sock_fd, recv_buf, sizeof(recv_buf), );
- fputs(recv_buf, stdout);
- strcpy(send_buf, recv_buf);
- send(sock_fd, send_buf, sizeof(send_buf), );
- return;
- }
- void listen_loop(unsigned int sock_fd)
- {
- int epollfd, i, ret;
- int timeout = ;
- struct epoll_event event;
- struct epoll_event eventList[];
- /*创建epoll监听事件*/
- epollfd = epoll_create();
- event.events = EPOLLIN | EPOLLET;
- event.data.fd = sock_fd;
- /*注册epoll监听事件.*/
- if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock_fd, &event) < ) {
- printf("register epoll event err !");
- return;
- }
- while () {
- ret = epoll_wait(epollfd, eventList, , timeout);
- /*epoll事件错误.*/
- if (ret < ) {
- printf("epoll event err!");
- break;
- }
- /*无事件返回.*/
- else if (ret == ) {
- continue;
- }
- /*epoll返回事件.*/
- for (i = ; i < ret; i++) {
- /*epoll 错误*/
- if ((eventList[i].events & EPOLLERR) || (eventList[i].events & EPOLLHUP) || !(eventList[i].events & EPOLLIN)) {
- printf("epoll error\n");
- close(eventList[i].data.fd);
- exit(-);
- }
- //half connection
- if (eventList[i].events & EPOLLRDHUP) {
- printf("//one client close the conne.//\n");
- close(eventList[i].data.fd);
- }
- /*accept事件*/
- if (eventList[i].data.fd == sock_fd) {
- accept_conn(sock_fd, epollfd);
- }
- /*非sock_fd则为其他事件.*/
- else {
- recv_message(eventList[i].data.fd);
- }
- }
- }
- close(epollfd);
- close(sock_fd);
- return;
- }
Linux下socket通信和epoll的更多相关文章
- Linux 下socket通信终极指南(附TCP、UDP完整代码)
linux下用socket通信,有TCP.UDP两种协议,网上的很多教程把两个混在了一起,或者只讲其中一种.现在我把自己这两天研究的成果汇总下来,写了一个完整的,适合初学者参考,也方便自己以后查阅. ...
- Linux下socket通信和多线程
服务端socket流程:socket() –> bind() –> listen() –> accept() –> 读取.发送信息(recv,send等) 客户端socket流 ...
- (8)Linux(客户端)和Windows(服务端)下socket通信实例
Linux(客户端)和Windows(服务端)下socket通信实例: (1)首先是Windows做客户端,Linux做服务端的程序 Windows Client端 #include <st ...
- Linux下进程通信的八种方法
Linux下进程通信的八种方法:管道(pipe),命名管道(FIFO),内存映射(mapped memeory),消息队列(message queue),共享内存(shared memory),信号量 ...
- linux下socket编程实例
linux下socket编程实例一.基本socket函数Linux系统是通过提供套接字(socket)来进行网络编程的.网络的socket数据传输是一种特殊的I/O,socket也是一种文件描述符.s ...
- (转)Linux下select, poll和epoll IO模型的详解
Linux下select, poll和epoll IO模型的详解 原文:http://blog.csdn.net/tianmohust/article/details/6677985 一).Epoll ...
- Linux下Socket编程的端口问题( Bind error: Address already in use )
Linux下Socket编程的端口问题( Bind error: Address already in use ) 在进行linux网络编程时,每次修改了源代码并再次编译运行时,常遇到下面的地使用错误 ...
- linux下串口通信与管理
linux下的串口与windows有一些区别,下面将介绍一下linux下串口通信管理 查看是否支持USB串口: #lsmod | grep usbserial 如果没有信息:sudo apt-get ...
- UNIX下socket通信 - UDP通信
一.UNIX下socket通信: socket套接字是一种可以进行网络通信的内核对象,它是一个唯一的标示符,一般称它为socket描述符. 注意:UDP通信需要客户端先发送消息,服务端先进行等待客户端 ...
随机推荐
- super函数的用法
1.创建一个类. # .创建一个类 class Bird: def __init__(self): self.hungry =True def eat(self): if self.hungry: p ...
- Day 18 正则表达式.
一.字符 .匹配除换行符以外的任意字符. \w 匹配字母数字或者下划线. \s 匹配任意的空白符 \d 匹配数字 \n 匹配一个换行符 \t 匹配一个制表符 ^ 匹配字符串的开始. $ 匹配字符串的结 ...
- 前端入门CSS(2)
参考: https://www.cnblogs.com/liwenzhou/p/7999532.html 背景属性 /*背景颜色*/background-color: red; /*背景图片*/ ba ...
- biz_platform项目过程
1.前台界面主要采用React框架.通过Ajax方式将数据与tornado服务器交互.以下代码为请求后台数据. var ThisPage = React.createClass({ render: f ...
- Spring MVC+MySQL保存中文变成乱码
环境:MySQL,Spring MVC3.2.0,jQuery v2.0.3,使用JdbcTemplate访问数据库,相当于全套Spring解决方案. 现象 直接使用表单POST,或者使用jQuery ...
- AQS源码泛读,梳理设计流程(jdk8)
一.AQS介绍 AQS(AbstractQueuedSynchronizer)抽象队列同步器,属于多线程编程的基本工具:JDK对其定义得很详细,并提供了多种常用的工具类(重入锁,读写锁,信号量,Cyc ...
- c malloc分配内存
php中的内存分配有用类似emalloc这样的函数,emalloc实际上是C语言中的malloc的一层封装,php启动后,会向OS申请一块内存,可以理解为内存池,以后的php分配内存都是在这块内存池中 ...
- 冒泡排序实现(Java)
冒泡排序是一种交换排序,它的基本思路是: 两两比较相邻记录的关键字,如果反序则交换,知道没有反序的记录位置. 依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一趟:首先比较第1个和第2个数, ...
- org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory$EnhancedResultObjectProxyImpl and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.
当我用Springboot和mybatis进行延迟加载时候报出如下的错误: org.apache.ibatis.executor.loader.javassist.JavassistProxyFact ...
- Android4.0 Launcher 源码分析1——Launcher整体结构
1.Launcher整体结构 桌面程序其实并不包含桌面壁纸,桌面壁纸其实是由 WallpaperManagerService来提供,整个桌面其实是叠加在整个桌面壁纸上的另外一个层. 1.1 WorkS ...