当前位置: 首页 > news >正文

Linux网络编程day9 libevent库

libevent库

开源。精简。跨平台(Windows,Linux,maxos)。专注于网络通信。

源码包安装:参考README
        1、./configure                检查安装环境 生成makefile

        2、make                        生成.o和执行文件

        3、sudo make install     将必要的资源拷贝至系统指定目录

        4、进入sample目录进行验证,运行demo验证库安装使用情况

        5、编译使用库的.c时,需要加 -levent

/usr/local/lib中可以查看到

特性

基于“事件”异步通信模型。----回调机制。 

libevent框架

1、创建event_base(底座)

struct event_base *event_base_new(void);struct event_base *base = event_base_new();

2、创建事件event

常规事件event

struct event *ev;
struct event* event_new(struct event_base* base , evutil_socket_t fd , 
short what , event_callback_fn cb , void*arg);base:event_base_new()返回值
fd:绑定到event上的文件描述符
what:对应监听的事件(读写异常)  EV_READ(一次读) EV_WRITE(一次写) EV_PERSIST(持续触发,结合循环生效使用)
cb:一旦事件满足监听条件,回调函数typedef void(*event_callback_fn)(evutil_socket_t fd , short , void*)
arg:回调函数参数
返回值:成功创建的事件
event_new();

bufferevent

bufferevent_socket_new();

3、将事件添加到base上

int event_add(struct event *ev , const struct timeval *tv);ev:event_new()函数返回值
tv:NULL不超时 回调函数一定被调用非0,等待时间返回值成功0失败-1
从base上摘下事件(了解)
int event_del(struct event *ev)

4、循环监听事件满足

int event_base_dispatch(struct event_base *base);

5、释放event_base

int event_base_free(base);

6、不常用一些函数

const char ** event_get_supported_methods(); // 查看支持的多路IO方法char *buf[10];buf = event_get_supported_methods();char buf[1024];
buf = event_base_get_method(base); // 查看目前的多路IO方法

事件的未决和非未决

未决:有资格被处理,但是还没有被处理

非未决:没有资格被处理

解释:事件被创建出来时是处于非未决状态,因为现在没有在base上,所以没有资格被处理,当调用event_add函数的时候,事件被插在base上,有资格被处理,故为未决态,当对应事件触发并且进入循环,事件会变为激活态,等回调函数被调用,事件被处理之后,事件又重新变为非未决态,如果设置了EV_PERSIST,事件会持续触发,变为未决态。 

带缓冲区的事件bufferevent 

#include<event2/bufferevent.h>

 bufferevent有两个缓冲区:也是队列实现的,只能读一次,先进先出(FIFO)。

 

 

创建销毁 

struct bufferevent *ev
struct bufferevent *bufferevent_socket_new(struct event_base*base , evutil_socket_t fd , enum bufferevent_options options);
base:event_base
fd:封装到bufferevent内的fd
options:BEV_OPT_CLOSE_ON_FREE    返回:成功创建的bufferevent对象
void bufferevent_socket_free(struct bufferevent *ev)

给读写缓冲区设置回调

对比event:event_new(base , fd , cb , void*arg);  event_add----挂到base

                    bufferevent_socket_new(fd)   bufferevent_setcb(call_back);

void bufferevent_setcb(struct bufferevent* bufev , bufferevent_data_cb readcb,bufferevent_data_cb writecb,bufferevent_event_cb eventcb,void*cbarg);
bufev:bufferevent_socket_new()函数返回值readcb:设置bufferevent读缓冲,对应回调read_cb(){ bufferevent_read()读数据 }writecb:设置bufferevent写缓冲,对应回调write_cb(){ } --给调用者发送写成功通知可以直接传NULLeventcb:设置事件回调,也可以传NULLcbarg:上述回调函数的参数read回调函数 
typedef void(*bufferevent_data_cb)(struct bufferevent* bufev , void*ctx);
eg. void read_cb(struct bufferevent* bufev , void*arg){bufferevent_read() //读数据}size_t bufferevent_read(struct bufferevent* bufev , void*data , size_t size);
在read_cb中代替read函数!!!
event回调函数
typedef void(*bufferevent_data_cb)(struct bufferevent* bufev , shot events , void*ctx);
void event_cb(struct bufferevent* bufev , shot events , void*arg)
{.......
}
events:BEV_EVENT_CONNECTED;
错误事件回调函数void event_cb(struct bufferevent *bev, short events, void *ctx) {if (events & BEV_EVENT_CONNECTED) {printf("✅ Connected to server.\n");} else if (events & BEV_EVENT_ERROR) {perror("❌ Error from bufferevent");} else if (events & BEV_EVENT_EOF) {printf("⚠️ Connection closed by server.\n");}
}

 

禁用、启用bufferevent缓冲区

默认新建的bufferevent写缓冲是enable,而读缓冲是disable

void bufferevent_enable(struct bufferevent* bufev , short events);events:EV_READ , EV_WRITE , EV_READ | EV_WRITE.void bufferevent_disable(struct bufferevent* bufev , short events);

网络通信

连接客户端

socket()、connect()

int bufferevent_socket_connect(struct bufferevent* bev , struct sockaddr*address , int addrlen);

服务器创建监听器服务器

socket()、bind()、listen()、accept()

下面这一个函数代替了上述四个函数的作用。

#include<event2/listener.h>struct evconnlistener* listener;struct evconnlistener* evconnlistener_new_bind(struct event_base*base , evconnlistener_cb cb, void* ptr , unsigned flags , int backlog , const struct sockaddr*sa , int socklen)flags:可识别的标志  |LEV_OPT_CLOSE_ON_FREE: 释放bufferevent时关闭底层传输端口(关闭套接字、释放底层)LEV_OPT_REUSEABLE :    端口复用backlog:-1默认使用最大值 listen参2返回值:成功创建的监听器。回调函数:一旦被回调,说明在其内部应该与客户端建立完成,数据读写操作,进行通信
typedef void(*evconnlistener_cb)(struct evconnlistener* listener , evutil_socket_t sock , struct sockaddr*addr , int len , void* ptr);sock:用于通信的文件描述符
addr:客户端的地址结构

回调函数调用成功表示:一旦被回调,说明在其内部应该与客户端建立完成,数据读写操作,进行通信。

服务器端libevent创建TCP连接

1.创建event_base

2.创建一个bufferevent事件对象 bufferevent_socket_new();

3.使用bufferevent_setcb()给bufferevent的read,write,event设置回调函数

4.当监听的事件满足时,read_cb会被调用,在其内部bufferevent_read()读操作

5.使用evconnlistener_new_bind创建一个监听服务器,设置其回调函数,当客户端成功连接时,回调函数会被调用

6.封装listener_cb回调函数。在函数内部完成和客户端通信

7.设置读缓冲和写缓冲的使能状态

8.启动循环监听event_base_dispatch();

9.释放连接

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<event2/bufferevent.h>
#include<ctype.h>
#include<event2/listener.h>
#define SER_PORT 9004void read_cb(struct bufferevent* bufev , void*arg)
{char buf[BUFSIZ];int n , i;n = bufferevent_read(bufev , buf , sizeof(buf));for(i = 0 ; i < n ; i++)buf[i] = toupper(buf[i]);bufferevent_write(bufev , buf , n);return;
}void write_cb(struct bufferevent* bufev , void*arg)
{printf("recived form client\n");return;
}void event_cb(struct bufferevent *bev, short events, void *ctx) {if (events & BEV_EVENT_CONNECTED) {printf("✅ Connected to server.\n");} else if (events & BEV_EVENT_ERROR) {perror("❌ Error from bufferevent");} else if (events & BEV_EVENT_EOF) {printf("⚠️ Connection closed by server.\n");}
}void listen_cb(struct evconnlistener* listener ,evutil_socket_t sock , struct sockaddr*addr , int len , void* ptr)
{struct event_base*base = (struct event_base*)ptr;struct bufferevent*bev = bufferevent_socket_new(base , sock , BEV_OPT_CLOSE_ON_FREE);bufferevent_setcb(bev , read_cb , write_cb , event_cb , NULL);bufferevent_enable(bev , EV_READ);//默认读缓冲是不可的,所以要设置成enablereturn;
}int main(int argc , char *argv[])
{struct event_base*base = event_base_new();struct sockaddr_in serv_addr;bzero(&serv_addr , sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SER_PORT);serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);struct evconnlistener*listener = evconnlistener_new_bind(base , listen_cb , base ,LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE , -1 , (struct sockaddr*)&serv_addr,sizeof(serv_addr));event_base_dispatch(base);evconnlistener_free(listener);event_base_free(base);return 0 ;
}

实现TCP客户端流程

1.创建event_base

2.创建一个bufferevent事件对象 bufferevent_socket_new();

3.使用bufferevent_setcb()给bufferevent的read,write,event设置回调函数

4.当监听的事件满足时,read_cb会被调用,在其内部bufferevent_read()读操作

6.使用bufferevent_socket_connect回调函数。建立连接

7.可以添加一个事件,用来用用户和终端交互,监听终端的写事件,就可以不用使用dup2

8.将监听事件挂在base上 event_add

8.启动循环监听event_base_dispatch();

9.释放连接

注意:先建立bufferevent_socket_new,创建出来缓冲区----bufferevent_setcb()----设置读缓冲使能bufferevent_enable()----建立连接bufferevent_socket_connect。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<event2/bufferevent.h>
#include<event2/event.h>
#include<fcntl.h>
#include<arpa/inet.h>
#define SER_PORT 9004void read_cb(struct bufferevent* bufev , void*arg)
{char buf[BUFSIZ];int n = bufferevent_read(bufev , buf , sizeof(buf)-1);if(n > 0){buf[n] =  '\0';printf("recived from server:%s\n" , buf);}else{printf("no data");}//bufferevent_write(bufev , buf , strlen(buf)+1);sleep(1);
}void write_cb(struct bufferevent* bufev , void*arg)
{printf("I am client , writing over\n");
}void event_cb(struct bufferevent *bev, short events, void *ctx) {if (events & BEV_EVENT_CONNECTED) {printf("✅ Connected to server.\n");} else if (events & BEV_EVENT_ERROR) {perror("❌ Error from bufferevent");} else if (events & BEV_EVENT_EOF) {printf("⚠️ Connection closed by server.\n");}
}void read_terminal(evutil_socket_t fd , short what , void*arg)
{struct bufferevent*bufev = (struct bufferevent*)arg;char buf[1024] = {0};int len = read(fd , buf , sizeof(buf));bufferevent_write(bufev , buf , len);
}int main(int argc , char *argv[])
{int fd = socket(AF_INET , SOCK_STREAM , 0);struct sockaddr_in serv_addr;bzero(&serv_addr , sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SER_PORT);inet_pton(AF_INET , "10.11.1.211" , &serv_addr.sin_addr);struct event_base*base = event_base_new();struct bufferevent*bufev;bufev = bufferevent_socket_new(base , fd , BEV_OPT_CLOSE_ON_FREE);bufferevent_setcb(bufev , read_cb , write_cb , event_cb , NULL);bufferevent_enable(bufev , EV_READ | EV_WRITE);bufferevent_socket_connect(bufev , (struct sockaddr*)&serv_addr , sizeof(serv_addr));struct event*ev = event_new(base , STDIN_FILENO , EV_READ | EV_PERSIST ,read_terminal , bufev);event_add(ev , NULL);event_base_dispatch(base);event_base_free(base);return 0 ;
}

http://www.xdnf.cn/news/394021.html

相关文章:

  • 代码随想录算法训练营第60期第三十二天打卡
  • RAII是什么?
  • 大学之大:东京工业大学2025.5.11
  • 误差函数(Error Function)的推导与物理意义
  • 【电机控制器】PY32MD310K18U7TR——ADC、UART
  • AAAI-2025 | 电子科大类比推理助力精准识别!SPAR:基于自提示类比推理的无人机目标探测技术
  • Java 线程池原理
  • 解决stm32HAL库使用vscode打开,识别不到头文件及uint8_t等问题
  • LOJ 6346 线段树:关于时间 Solution
  • 假如你的项目是springboot+vue怎么解决跨域问题
  • Anaconda环境中conda与pip命令的区别
  • Java--图书管理系统(简易版)
  • 信息安全管理与评估索引
  • 02.three官方示例+编辑器+AI快速学习webgl_animation_skinning_blending
  • C++类和对象--初阶
  • 英伟达微调qwen2.5-32B模型,开源推理模型:OpenCodeReasoning-Nemotron-32B
  • 关于 js:6. 网络与加密模块
  • JUC并发编程(上)
  • suricata之规则去重
  • 力扣刷题(第二十三天)
  • LLMs之MCP:2025年5月2日,Anthropic 宣布 Claude 重大更新:集成功能上线,研究能力大幅提升
  • 关于在使用getOutputStream()方法后续没有用到write()
  • 普通IT的股票交易成长史--20250511 美元与美股强相关性
  • 微服务架构中如何保证服务间通讯的安全
  • 实践官方的 A2A SDK Python
  • 理解c++中explicit关键字的作用
  • Ai学习之LLM
  • python-Pandas库详细教程
  • C++蓝桥杯真题(题目+解析+流程图)(特殊运算符+四叶玫瑰数+质因数的个数+最大的矩形纸片+数字游戏+活动人数)
  • ADC接口