Libevent -- epoll reactor model

I'll explore the way ahead 2020-11-13 03:41:49
libevent epoll reactor model


One 、epoll The server :

epoll — The server — monitor — fd ---- Can be read ---- epoll return ---- read — Small to capital — write ---- epoll Keep listening .

epoll Reactor model :

establish efd(epoll_create) ---- increase fd(epoll_ctl) ---- epoll_wait return ----fd Can be read ---- read ---- fd Pick from the tree ---- Set listening fd Write events , operation senddata ---- Small to capital ( Or a direct shot back ) ---- wait for epoll_wait return ---- Write back to the client ----efd Pick from the tree ---- Set listening cfd Read events , operation recvdata----epoll Keep listening

1. Added judgment fd Can I write , Due to the sliding window mechanism, the server can not pass through at the moment fd Write data back to the client .
2.evt[i].events = EPOLLIN;evt[I].data.fd It's not a simple delivery fd 了 , It's passing a pointer ( Structure pointer )*ptr
 1 /*
2 *epoll Based on non blocking I/O Event driven
3 */
#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 // The upper limit the red black tree can listen to 
#define BUFLEN 4096
#define SERV_PORT 8080
void recvdata(int fd, int events, void *arg);
void senddata(int fd, int events, void *arg);
/* Describes information about ready file descriptors */
struct myevent_s {

int fd; // The file descriptor to listen to 
int events; // The corresponding listening event 
void *arg; // The generic parameter 
void(*call_back)(int fd, int events, void *arg); // Callback function 
int status; // Is it listening :1-> On the red and black trees ( monitor ), 0-> be not in ( No monitoring )
char buf[BUFLEN];
int len;
long last_active; // Record every time you add a red black tree g_efd Time value of ( If you don't send data for a long time , Then kick it out ),eventset and add This time will be reset 
};
int g_efd; // Global variables , preservation epoll_create File descriptor returned 
struct myevent_s g_events[MAX_EVENTS + 1]; // Custom structure type array . +1-->listen fd
/* The structure myevent_s Member variables initialization */
// Callback function call_back Parameters of arg It's the structure myevent_s In itself 
void eventset(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); // call eventset Time of function ( Once called, it changes ), If it hasn't changed for a long time ( Confiscating data ), It will be deleted 
return;
}
/* towards epoll Monitoring the red and black tree Add one File descriptor */
void eventadd(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; //EPOLLIN or EPOLLOUT
if (ev->status == 1) // Already in the red and black tree g_efd in 
{

op = EPOLL_CTL_MOD; // Modify its properties 
}
else{
 // Not in the red and black trees g_efd in 
op = EPOLL_CTL_ADD; // Add it to the red black tree g_efd, And will status Set up 1
ev->status = 1;
}
if (epoll_ctl(efd, op, ev->fd, &epv) < 0) // Actual addition / modify 
printf("event add failed [fd=%d], events[%d]\n", ev->fd, events);
else
printf("event add OK [fd=%d], op=%d, events[%0X]\n", ev->fd, op, events);
return;
}
/* from epoll Monitoring Delete one from the red and black tree File descriptor */
void eventdel(int efd, struct myevent_s *ev)
{

struct epoll_event epv = {
 0, {
 0 } };
if (ev->status != 1) // Not on the black and red tree 
return;
//epv.data.ptr = ev;
epv.data.ptr = NULL;
ev->status = 0; // modify state 
epoll_ctl(efd, EPOLL_CTL_DEL, ev->fd, &epv); // From the red and black trees efd Admiral ev->fd Enucleation 
return;
}
/* When a file descriptor is ready , epoll return , Call this function Link with client */
void acceptconn(int lfd, int events, void *arg)
{

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) {

/* No error handling for the time being */
}
printf("%s: accept, %s\n", __func__, strerror(errno));//__func__ The current corresponding function name 
return;
}
do {

for (i = 0; i < MAX_EVENTS; i++) // From global array g_events Find a free element in 
if (g_events[i].status == 0) // Be similar to select The median value is -1 The elements of 
break; // Jump out of for
if (i == MAX_EVENTS) {

printf("%s: max connect limit[%d]\n", __func__, MAX_EVENTS);
break; // Jump out of do while(0) Do not execute subsequent code 
}
int flag = 0;
if ((flag = fcntl(cfd, F_SETFL, O_NONBLOCK)) < 0) {
 // take cfd Also set to non blocking 
printf("%s: fcntl nonblocking failed, %s\n", __func__, strerror(errno));
break;
}
/* to cfd Set up a myevent_s Structure , Callback function Set to recvdata */
eventset(&g_events[i], cfd, recvdata, &g_events[i]); // The callback function has changed 
eventadd(g_efd, EPOLLIN, &g_events[i]); // take cfd Add to the red black tree g_efd in , Listen to read events 
} 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 recvdata(int fd, int events, void *arg)
{

struct myevent_s *ev = (struct myevent_s *)arg;
int len;
//recv Specifically for reading sockets ,recv The last pass 0 Just like read The same 
len = recv(fd, ev->buf, sizeof(ev->buf), 0); // Read file descriptor , Data stored in myevent_s member buf in 
eventdel(g_efd, ev); // Remove the node from the red and black tree 
if (len > 0) {

ev->len = len;
ev->buf[len] = '\0'; // Add string end tag manually 
printf("C[%d]:%s\n", fd, ev->buf);
eventset(ev, fd, senddata, ev); // Set the fd The corresponding callback function is senddata
eventadd(g_efd, EPOLLOUT, ev); // take fd Join the red and black trees g_efd in , Listen to its write events 
}
else if (len == 0) {

close(ev->fd);
/* ev-g_events The offset element position is obtained by subtracting the address */
printf("[fd=%d] pos[%ld], closed\n", fd, ev - g_events);
}
else {

close(ev->fd);
printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
}
return;
}
void senddata(int fd, int events, void *arg)
{

struct myevent_s *ev = (struct myevent_s *)arg;
int len;
len = send(fd, ev->buf, ev->len, 0); // Directly transfer data Write back to the client . Not processed 
/*
175 printf("fd=%d\tev->buf=%s\ttev->len=%d\n", fd, ev->buf, ev->len);
176 printf("send len = %d\n", len);
177 */
eventdel(g_efd, ev); // From the red and black trees g_efd Remove 
if (len > 0) {

printf("send[fd=%d], [%d]%s\n", fd, len, ev->buf);
eventset(ev, fd, recvdata, ev); // Will be fd Of The callback function is changed to recvdata
eventadd(g_efd, EPOLLIN, ev); // From the new add to the red and black tree , Set to listen for read events 
}
else {

close(ev->fd); // Close links 
printf("send[fd=%d] error %s\n", fd, strerror(errno));
}
return;
}
/* establish socket, initialization lfd */
void initlistensocket(int efd, short port)
{

struct sockaddr_in sin;
int lfd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(lfd, F_SETFL, O_NONBLOCK); // take socket Set to non blocking 
memset(&sin, 0, sizeof(sin)); //bzero(&sin, 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);
/* The structure myevent_s Member variables initialization */ // The parameters passed by the callback function are the structure itself 
/* void eventset(struct myevent_s *ev, int fd, void (*call_back)(int, int, void *), void *arg); */
eventset(&g_events[MAX_EVENTS], lfd, acceptconn, &g_events[MAX_EVENTS]);// Direct will listenfd Put it at the end of the array 
/* towards epoll Monitoring the red and black tree Add one File descriptor */
/* void eventadd(int efd, int events, struct myevent_s *ev) */
eventadd(efd, EPOLLIN, &g_events[MAX_EVENTS]);
return;
}
int main(int argc, char *argv[])
{

unsigned short port = SERV_PORT;
if (argc == 2)
port = atoi(argv[1]); // Use user specified port . If not specified , Use default port 
g_efd = epoll_create(MAX_EVENTS + 1); // Create a red black tree , Back to the big picture g_efd 
if (g_efd <= 0)
printf("create efd in %s err %s\n", __func__, strerror(errno));
initlistensocket(g_efd, port); // Initialize listening socket
struct epoll_event events[MAX_EVENTS + 1]; // Save an array of file descriptors that have satisfied the ready event 
printf("server running:port[%d]\n", port);
int checkpos = 0, i;
while (1) {

/* Timeout verification , Every test 100 A link , Don't test listenfd When the client 60 No communication with the server in seconds , Then close the client link */
long now = time(NULL); // current time 
for (i = 0; i < 100; i++, checkpos++)
{
 // Primary cycle detection 100 individual . Use checkpos Control test object 
if (checkpos == MAX_EVENTS)
checkpos = 0;
if (g_events[checkpos].status != 1) // Not in the red and black trees g_efd On 
continue;
long duration = now - g_events[checkpos].last_active; // The world where the client is not active 
if (duration >= 60)
{

close(g_events[checkpos].fd); // Close the link with the client 
printf("[fd=%d] timeout\n", g_events[checkpos].fd);
eventdel(g_efd, &g_events[checkpos]); // Put the client From the red and black trees g_efd remove 
}
}//for
/* Monitor the red black tree g_efd, Add the event descriptor to the file events Array , 1 Second no event satisfies , return 0*/
int 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++)
{

/* Use custom structs myevent_s Type a pointer , receive Consortium data Of void *ptr member */
struct myevent_s *ev = (struct myevent_s *)events[i].data.ptr;
if ((events[i].events & EPOLLIN) && (ev->events & EPOLLIN))
{
 // Read ready event 
ev->call_back(ev->fd, events[i].events, ev->arg);
}
if ((events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT))
{
 // Write ready event 
ev->call_back(ev->fd, events[i].events, ev->arg);
}
}//for
}//while(1)
/* Release all resources before exiting */
return 0;
}
版权声明
本文为[I'll explore the way ahead]所创,转载请带上原文链接,感谢

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple