想写一个关于反应堆的技术博客。
先占个坑吧。
epoll反应堆:

/*
* epoll 基于非阻塞I/O事件驱动
*/#include <stdio.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>#define MAX_EVENTS 1024
#define BUFLEN 4096
#define SERV_PORT 8080
#define TIME_OUT_SECOND 10void recv_data(int fd, int events, void *arg);
void send_data(int fd, int events, void *arg);/*描述就绪文件描述符相关信息
*/struct myevent_s
{int fd;                                           //要监听的文件描述符int events;                                       //对应的监听事件void *arg;                                        //泛型参数void (*call_back)(int fd, int events, void *arg); //回调函数int status;char buf[BUFLEN];int len;long last_active; //记录每次加入红黑树g_efd的时间
};int g_efd;                                 //epoll_create返回的全局句柄
struct myevent_s g_events[MAX_EVENTS + 1]; //自定义结构体泛型数组,+1-->listen fd;/*
struct epoll_event
结构体epoll_event被用于注册所感兴趣的事件和回传所发生待处理的事件,定义如下:struct epoll_event
{__uint32_t events;       epoll event epoll_data_t data;       User data variable
};
typedef union epoll_data
{void *ptr;int fd;__uint32_t u32;__uint64_t u64;
} epoll_data_t; //保存触发事件的某个文件描述符相关的数据
*///初始化结构体
void event_set(struct myevent_s *ev, int fd, void (*call_back)(int, int, void *), void *arg)
{ev->fd = fd;ev->call_back = call_back;ev->events = 0;ev->arg = arg;ev->status = 0;// memset(ev->buf, 0, sizeof(ev->buf));// ev->len = 0;ev->last_active = time(NULL); //调用event的时间return;
}//将fd添加到epoll注册的事件合集
void event_add(int efd, int events, struct myevent_s *ev)
{struct epoll_event epv = {0, {0}};int op;epv.data.ptr = ev;epv.events = ev->events = events;if (ev->status == 1){op = EPOLL_CTL_MOD;}else{op = EPOLL_CTL_ADD;ev->status = 1;}if (epoll_ctl(efd, op, ev->fd, &epv) < 0){printf("event add failed [fd=%d], events[%d]\n", ev->fd, events);}else{return;printf("event add OK [fd=%d], op=%d, events[%0X]\n", ev->fd, op, events);}return;
}//从事件合集中删除
void event_del(int efd, struct myevent_s *ev)
{struct epoll_event epv = {0, {0}};if (ev->status != 1){return;}epv.data.ptr = ev;ev->status = 0;epoll_ctl(efd, EPOLL_CTL_DEL, ev->fd, &epv);return;
}//当有新的连接时,调用监听listenfd的此回调函数,指定新sockfd的回调函数
void accept_conn(int lfd, int events, void *arg)
{printf("****************************\n");struct sockaddr_in cin;socklen_t len = sizeof(cin);int cfd, i;if ((cfd = accept(lfd, (struct sockaddr *)&cin, &len)) == -1){if (errno != EAGAIN && errno != EINTR){/* 暂时不做出错处理 */}printf("%s: accept, %s\n", __func__, strerror(errno));return;}do{for (i = 0; i < MAX_EVENTS; i++){if (g_events[i].status == 0){break;}}if (i == MAX_EVENTS){printf("%s: max connect limit[%d]\n", __func__, MAX_EVENTS);break;}int flag = 0;if ((flag = fcntl(cfd, F_SETFL, O_NONBLOCK)) < 0){printf("%s: fcntl nonblocking failed, %s\n", __func__, strerror(errno));break;}event_set(&g_events[i], cfd, recv_data, &g_events[i]);event_add(g_efd, EPOLLIN, &g_events[i]);} while (0);printf("new connect [%s:%d][time:%ld], pos[%d]\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), g_events[i].last_active, i);return;
}void recv_data(int fd, int events, void *arg)
{struct myevent_s *ev = (struct myevent_s *)arg;int len;len = recv(fd, ev->buf, sizeof(ev->buf), 0);event_del(g_efd, ev); //接受完数据 删除该监听事件if (len > 0){ev->len = len;ev->buf[len] = '\0';//printf("%s[%d]@%s,\t C[%d]:%s\n", __func__, __LINE__, __FILE__, fd, ev->buf);/* 转换为发送事件 */event_set(ev, fd, send_data, ev);event_add(g_efd, EPOLLOUT, ev); //再把其添加到监听事件中,此时回调函数改为了send_data//将socket事件修改为EPOLLOUT用于服务器发送消息给客户端}else if (len == 0){close(ev->fd);/* ev-g_events 地址相减得到偏移元素位置 */printf("%s[%d]@%s,\t[fd=%d] pos[%d], closed\n", __func__, __LINE__, __FILE__, fd, (int)(ev - g_events));}else{close(ev->fd);printf("%s[%d]@%s,\trecv[fd=%d] error[%d]:%s\n", __func__, __LINE__, __FILE__, fd, errno, strerror(errno));}return;
}void send_data(int fd, int events, void *arg)
{struct myevent_s *ev = (struct myevent_s *)arg;int len;len = send(fd, ev->buf, ev->len, 0);// printf("fd=%d\tev->buf=%s\ttev->len=%d\n", fd, ev->buf, ev->len);// printf("send len = %d\n", len);event_del(g_efd, ev); //删除该事件if (len > 0){//printf("send[fd=%d], [%d]%s\n", fd, len, ev->buf);event_set(ev, fd, recv_data, ev);event_add(g_efd, EPOLLIN, ev); //添加该事件,已更改回调函数为recv_data//修改socket事件为EPOLLIN用于接收客户端发来的消息}else{close(ev->fd);printf("send[fd=%d] error %s\n", fd, strerror(errno));}return;
}//初始化一个sockfd
void init_listen_socket(int efd, short port)
{int lfd = socket(AF_INET, SOCK_STREAM, 0);fcntl(lfd, F_SETFL, O_NONBLOCK);event_set(&g_events[MAX_EVENTS], lfd, accept_conn, &g_events[MAX_EVENTS]);event_add(efd, EPOLLIN, &g_events[MAX_EVENTS]);struct sockaddr_in sin;memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;sin.sin_addr.s_addr = INADDR_ANY;sin.sin_port = htons(port);bind(lfd, (struct sockaddr *)&sin, sizeof(sin));listen(lfd, 20);return;
}int main(int argc, char const *argv[])
{unsigned short port = SERV_PORT;if (argc == 2){port = atoi(argv[1]);}g_efd = epoll_create(MAX_EVENTS + 1); //创建红黑树,返回全局fdif (g_efd < 0){printf("create efd in %s err %s\n", __func__, strerror(errno));exit(-1);}init_listen_socket(g_efd, port);           //初始化监听套接字struct epoll_event events[MAX_EVENTS + 1]; //保存就绪事件的文件描述符数组printf("Server running: port [%d]\n", port);int checkpos = 0, i = 0;while (1){ //超时验证,每次测试100个连接,不测试listenfd 当客户端TIME_OUT_SECOND秒内没有和服务器通信,则关闭此客户端连接long now = time(NULL);for (i = 0; i < 100; i++, checkpos++){if (checkpos == MAX_EVENTS)checkpos = 0;if (g_events[checkpos].status != 1) //不在红黑树上continue;long duration = now - g_events[checkpos].last_active;if (duration >= TIME_OUT_SECOND) //超时,关闭连接{close(g_events[checkpos].fd);printf("[fd=%d] timeout\n", g_events[checkpos].fd);event_del(g_efd, &g_events[checkpos]); //将客户端从红黑树摘除}}//监听红黑树,将就绪事件文件描述符加入到events数组中,1秒没有事件满足,返回0int nfd = epoll_wait(g_efd, events, MAX_EVENTS + 1, 1000);if (nfd < 0){printf("epoll wait error, exit\n");break;}for (i = 0; i < nfd; i++){//使用自定义结构体myevents_s指针,接受,联合体data 的void* ptr成员struct myevent_s *ev = (struct myevent_s *)events[i].data.ptr;if ((events[i].events & EPOLLIN) && (ev->events & EPOLLIN)) //读就绪ev->call_back(ev->fd, events[i].events, ev->arg);if ((events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT)) //写就绪ev->call_back(ev->fd, events[i].events, ev->arg);}}return 0;
}

客户端代码

/*************************************************************************> Copyright(c)  NEWPLAN, all rights reserved.> File Name   : client.c> Author      : NEWPLAN> Mail        : newplan001@163.com> Created Time: 2018年11月06日 星期二 16时22分01秒************************************************************************/#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
static void userHelp(char *str)
{printf("%s [server_ip] [server_port]", str);
}
int main(int argc, char *argv[])
{if (argc != 3){userHelp(argv[0]);return 1;}int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0){perror("sock()");exit(-1);}struct sockaddr_in client;client.sin_family = AF_INET;client.sin_port = htons(atoi(argv[2]));client.sin_addr.s_addr = inet_addr(argv[1]);if (connect(sock, (struct sockaddr *)&client, sizeof(client)) < 0){perror("connect()");exit(-2);}size_t index = 0;struct timeval start, stop, diff;gettimeofday(&start, 0);while (1){char buffer[1024] = "hello world!";ssize_t s = 1024;//printf("please input:");//fflush(stdout);//ssize_t s = read(0, buffer, sizeof(buffer) - 1);if (s > 0){buffer[s - 1] = 0;write(sock, buffer, strlen(buffer));ssize_t _s = read(sock, buffer, sizeof(buffer) - 1);if (_s > 0){buffer[_s] = 0;//printf("server echo# %s\n", buffer);}}if (index++ % 1000000 == 0){gettimeofday(&stop, 0);long res = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;printf("index: %lu, rate: %10f MB/s\n", index, 1.024 * 1.024 * 8 * 1000000.0 / 1024 / (res / 1000000.0));start = stop;}}return 0;
}

参考:

https://blog.csdn.net/libaineu2004/article/details/70197825
http://www.voidcn.com/article/p-zicwwtwg-bgt.html
http://www.voidcn.com/article/p-dnykptrv-bgt.html
http://www.voidcn.com/article/p-mbyuzire-bkx.html
https://blog.csdn.net/drdairen/article/details/53694550
github 多线程 reactor

IO多路复用和epoll反应堆相关推荐

  1. IO多路复用之epoll总结 http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html

    IO多路复用之epoll总结 http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html

  2. linux IO多路复用 select epoll

    概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程 通俗理解(摘自网上一大神) 这些名词比较绕口,理解涵义就好.一个epoll场景:一个酒吧服务员(一个线程),前 ...

  3. IO多路复用之epoll总结

    1.基本知识 epoll是在2.6内核中提出的,是之前的select和poll的增强版本.相对于select和poll来说,epoll更加灵活,没有描述符限制.epoll使用一个文件描述符管理多个描述 ...

  4. Socket IO多路复用: epoll原理图解

    目录 一.accept 创建新 socket 1.1 初始化 struct socket 对象 1.2 为新 socket 对象申请 file 1.3 接收连接 1.4 添加新文件到当前进程的打开文件 ...

  5. IO多路复用之epoll模型

    一.IO多路复用:一个线程监测多个IO操作 基本思想:先构造一张有关描述符的表,然后调用一个函数,当这些文件描述符中的一个或多个已经准备好进行I/O函数时才返回.函数返回时告诉进程哪个描述符已经就绪, ...

  6. IO多路复用机制——epoll

    高效地对海量用户提供服务,必须要让进程能同时处理很多个tcp连接.假设一个进程保持了10000条连接,如何发现哪条连接上有数据可读.可写? 实现:循环遍历来发现IO事件?效率太低了. 目录 IO模型 ...

  7. 【Linux系统编程】IO多路复用之epoll

    00. 目录 文章目录 00. 目录 01. 概述 02. epoll函数 03. 程序示例 04. epoll优缺点 05. 附录 01. 概述 epoll是Linux下多路复用IO接口select ...

  8. python网络编程——IO多路复用之epoll

    什么是epoll epoll是什么?在linux的网络编程中,很长的时间都在使用select来做事件触发.在linux新的内核中,有了一种替换它的机制,就是epoll.当然,这不是2.6内核才有的,它 ...

  9. IO多路复用之epoll

    一.epoll函数族 1. 函数epoll_creat: 该函数生成一个epoll专用的文件描述符 #include <sys/epoll.h> int epoll_creae(int s ...

  10. Linux IO多路复用之epoll网络编程(含源码)

    前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一 ...

最新文章

  1. rhel6ACL权限
  2. hdu 2777(线段树)
  3. Hbase Compaction 源码分析 - RatioBasedCompactionPolicy 策略
  4. 图像质量评价指标: PSNR 和 SSIM
  5. Java多线程——同步问题
  6. python 颜色空间转换_python opencv入门 颜色空间转换(9)
  7. windows10杀死本地进程
  8. ae 地理坐标与投影坐标转换 [转]
  9. 黑幕背后的Autorelease
  10. 需要获取trustedinstaller权限才能删除文件,删不了
  11. 阿里云服务器密码重置
  12. MAC M1安装VMware 安装windows11
  13. 腾讯对战平台显示版本服务器连接超时,腾讯对战平台怎么了_腾讯对战平台出现问题怎么解决...
  14. 智能音箱音效哪个好_四大智能音箱,你觉得哪个才是最好用的?
  15. 冒泡php_PHP实现冒泡排序
  16. mysql——时间显示格式 dateformat函数
  17. b树与b 树的区别 mysql,B树和B+树
  18. 3.3 测试实现标准的ZIO服务
  19. 基于高德地图实现的公交线路查询功能
  20. 常见的SQL注入类型

热门文章

  1. lstm token分类模型代码解析(直接传入batch数据,测试pad和pack_padded、pad_packed三函数)
  2. MATLAB中plot函数的用法
  3. Java SE 070 Retention及RetentionPolicy详解
  4. ThinkPad产品进入BIOS的方法
  5. 答应了邮件offer还能反悔吗?
  6. oracle datamodeler,查看您的 Oracle SQL Developer Data Modeler 设计
  7. SpringBoot整合Activiti Modeler可视化流程定制
  8. 用map集合形容朋友
  9. SQL Server LEFT函数
  10. ISO8601标准时间格式