【Linux系统编程】libevent库bufferevent与evconnlistener
libevent库bufferevent与evconnlistener
介绍
bufferevent是libevent提供的一个自带输入输出缓冲区的事件模型,bufferevent监听socket文件描述符的读写等事件,并自动将内核缓冲区中的数据读写到用户区的缓冲区,并自动触发相应的回调函数。
evconnlistener封装了socket、bind、listen、accept几个函数,当有客户端连接的时候,自动accept并调用回调函数。
相关函数
bufferevent_socket_new()
函数说明
基于一个已有的socket创建一个socket bufferevent。
函数原型
#include <event2/bufferevent.h>
struct bufferevent* bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options);
函数参数
struct event_base *base
:添加事件的event_base结构体。evutil_socket_t fd
:需要监听的socket文件描述符。int options
:配置标志BEV_OPT_THREADSAFE
:使bufferevent能够在多线程下是安全的BEV_OPT_CLOSE_ON_FREE
:释放buffer_event时,自动关闭底层接口(关闭文件描述符)
函数返回值
- 成功返回
bufferevent
的结构体指针 - 失败返回nullptr
bufferevent_socket_connect()
函数说明
连接到对端socket,自动绑定配置bufferevent。
函数原型
int bufferevent_socket_connect(struct bufferevent *bufev, const struct sockaddr *addr, int socklen);
函数参数
struct bufferevent *bufev
:需要绑定的bufferevent结构体指针。const struct sockaddr *addr
:要连接的对端sockaddr信息。int socklen
:第二个参数的大小。
函数返回值
- 成功返回0,失败返回-1
void bufferevent_free(struct bufferevent *bufev)
函数说明
释放bufferevent
函数参数
struct bufferevent *bufev
:要释放的bufferevent结构体指针
bufferevent_setcb()
函数说明:设置bufferevent的回调函数。
函数原型
void bufferevent_setcb(
struct bufferevent *bufev,
bufferevent_data_cb readcb,
bufferevent_data_cb writecb,
bufferevent_event_cb eventcb,
void *cbarg
);
函数参数
struct bufferevent *bufev
:要设置回调函数的buffereventbufferevent_data_cb readcb
:读事件回调函数bufferevent_data_cb writecb
:写事件回调函数typedef void(* bufferevent_data_cb) (struct bufferevent *bev, void *ctx)
:bev是调用该函数的bufferevent结构体指针,ctx是用户定义上下文的指针,用来传递参数
bufferevent_event_cb eventcb
:特殊事件回调函数typedef void(* bufferevent_event_cb) (struct bufferevent *bev, short what, void *ctx)
:what用来标识发生了什么事件BEV_EVENT_EOF
:遇到文件结束指示BEV_EVENT_ERROR
:发生错误BEV_EVENT_TIMEOUT
:发生超时BEV_EVENT_CONNECTED
:请求的过程中连接已经完成
void *cbarg
:回调函数的参数
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
函数说明:从bufferevent的缓冲区读取数据到data,data大小为size(最大读入size大小),返回实际读入的数据长度。
int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
函数说明:将data中的数据写到bufferevent的缓冲区,大小为size,返回实际写入的数据长度。
int bufferevent_enable(struct bufferevent *bufev, short event)
函数说明:使能bufferevent的回调函数。
函数参数
short event
:要使能的事件,可为EV_READ | EV_WRITE
的组合。
int bufferevent_disable(struct bufferevent *bufev, short event)
函数说明:失能相关事件。
evconnlistener_new_bind()
函数说明:创建套接字并连接,同时初始化evconnlistener。
函数原型
struct evconnlistener* evconnlistener_new_bind(
struct event_base *base,
evconnlistener_cb cb,
void *ptr,
unsigned flags,
int backlog,
const struct sockaddr *sa,
int socklen
)
函数参数
evconnlistener_cb cb
:监听事件的回调函数
-typedef void(* evconnlistener_cb) (struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *)
:参数分别为evconnlistener的结构体指针、客户端连接的文件描述符、客户端地址端口信息、sockaddr长度、自定义的参数指针。void *ptr
:回调函数参数unsigned flags
:配置标志LEV_OPT_LEAVE_SOCKETS_BLOCKING
:文件描述符为阻塞的LEV_OPT_CLOSE_ON_FREE
关闭时自动释放LEV_OPT_REUSEABLE
:端口复用LEV_OPT_THREADSAFE
:分配锁, 线程安全
int backlog
:全连接队列长度,使用-1自动配置const struct sockaddr *sa
:用来监听的ip、端口、协议,与手动bind相同
void evconnlistener_free(struct evconnlistener *lev)
函数说明:释放evconnlistener。
int evconnlistener_enable(struct evconnlistener *lev)
函数说明:使能evconnlistener回调函数。
int evconnlistener_disable(struct evconnlistener *lev)
函数说明:失能evconnlistener回调函数。
实现TCP服务端
#include <iostream>
#include <cstring>
#include <cerrno>
#include <arpa/inet.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
using namespace std;
event_base *eb;
void listener_cb (struct evconnlistener *, evutil_socket_t, struct sockaddr *, int, void *);
void read_cb (struct bufferevent *bev, void *ctx);
int main(int argc, char *argv[]) {
// 创建监听事件
eb = event_base_new();
sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(8886);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
evconnlistener *listener =
evconnlistener_new_bind(eb,
listener_cb, nullptr,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
-1, (sockaddr*)&sa, sizeof(sa));
event_base_dispatch(eb);
evconnlistener_free(listener);
event_base_free(eb);
}
void listener_cb (struct evconnlistener *listener,
evutil_socket_t cfd,
struct sockaddr *csa,
int socklen,
void *ctx) {
sockaddr_in *csai = (sockaddr_in*)csa;
int cport = ntohs(csai->sin_port);
char cip_chars[16];
if (nullptr == inet_ntop(AF_INET, &(*csai).sin_addr.s_addr, cip_chars, sizeof(cip_chars))) {
perror("inet_ntop");
exit(-1);
}
cout << "Accept Client " << cip_chars << ":" << cport << endl;
bufferevent *bufev = bufferevent_socket_new(eb, cfd, BEV_OPT_CLOSE_ON_FREE);
if (bufev == nullptr) {
perror("bufferevent_socket_new");
exit(-1);
}
bufferevent_setcb(bufev, read_cb, nullptr, nullptr, csai);
bufferevent_enable(bufev, EV_READ);
}
void read_cb (struct bufferevent *bev, void *ctx) {
char buffer[1024];
memset(buffer, 0x00, sizeof(buffer));
sockaddr_in *csai = (sockaddr_in*)ctx;
int size = bufferevent_read(bev, buffer, sizeof(buffer));
int cport = ntohs(csai->sin_port);
char cip_chars[16];
if (nullptr == inet_ntop(AF_INET, &(*csai).sin_addr.s_addr, cip_chars, sizeof(cip_chars))) {
perror("inet_ntop");
exit(-1);
}
cout << "Recived Message From Client " << cip_chars << ":" << cport << " ";
cout << buffer << endl;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2023-04-14 MinGW是啥
2023-04-14 1.计算机视觉概述
2023-04-14 【LBLD】我写了首诗,让你闭着眼睛也能写对二分搜索