• 正文
  • 相关推荐
申请入驻 产业图谱

嵌入式开发必备:开源事件驱动库 libevent

2025/07/23
3990
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

上一篇我们分享了:libevhtp——一款专为嵌入式系统设计的开源HTTP库!,libevhtp依赖于libevent。这篇文章我们一起来了解libevent。

一、libevent 简介

libevent 是一个开源的、轻量级的跨平台事件驱动库:

Github仓库地址:https://github.com/libevent/libevent

libevent 的源码结构清晰,主要分为以下几个核心模块:

libevent/
├── event.c                # 事件核心逻辑
├── epoll.c               # Linux epoll 后端实现
├── kqueue.c              # BSD kqueue 后端实现
├── select.c              # 通用 select 后端实现
├── bufferevent.c         # 缓冲区事件处理
├── evhttp.c              # HTTP 协议处理
├── evdns.c               # DNS 解析模块
├── evthread.c            # 线程支持
├── evutil.c              # 工具函数

封装了多种操作系统的 I/O 多路复用机制(如 epoll、kqueue、select 等),提供了统一的事件处理接口,极大简化了异步网络编程的复杂度。

1. 核心特性

  • 跨平台支持:原生支持 Linux、Windows、BSD 等多种操作系统,甚至在嵌入式系统上也能运行
  • 高性能 I/O 模型:自动适配底层最优的 I/O 多路复用机制(epoll/kqueue 优先)
  • 轻量级设计:核心代码简洁高效,资源占用低,非常适合嵌入式场景
  • 丰富的功能组件:包含 HTTP 服务器、DNS 解析、SSL 支持等实用模块
  • 线程安全:提供完善的线程安全机制,支持多线程环境下的事件处理

2. 优缺点分析

二、libevent实战

1. 源码获取与编译

# 克隆源码仓库
git clone https://github.com/libevent/libevent.git
cd libevent

# 创建编译目录
mkdir build && cd build

# 使用 CMake 配置(嵌入式平台需指定交叉编译工具链)
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/libevent

# 编译
make -j16

# 安装到指定目录
sudo make install

2. 简单的 TCP 服务器

下面是一个基于 libevent 的简单 TCP 服务器示例,实现了接收客户端连接并回显数据的功能:

#include <event2/event.h>
#include <event2/listener.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/* 客户端连接处理回调函数 */
void client_read_cb(struct bufferevent *bev, void *ctx) {
char buffer[1024];
int len;

/* 从缓冲区读取数据 */
len = bufferevent_read(bev, buffer, sizeof(buffer) - 1);
if (len <= 0) {
printf("客户端连接关闭n");
bufferevent_free(bev);
return;
}

buffer[len] = '';
printf("收到客户端数据: %s", buffer);

/* 将数据回显给客户端 */
bufferevent_write(bev, buffer, len);
}

/* 客户端连接错误处理回调 */
void client_event_cb(struct bufferevent *bev, short events, void *ctx) {
if (events & BEV_EVENT_EOF) {
printf("客户端断开连接n");
} elseif (events & BEV_EVENT_ERROR) {
printf("客户端发生错误n");
} elseif (events & BEV_EVENT_CONNECTED) {
printf("客户端连接成功n");
}
bufferevent_free(bev);
}

/* 新客户端连接处理回调 */
void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t sock,
struct sockaddr *addr, int len, void *ctx) {
struct event_base *base = evconnlistener_get_base(listener);
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
char client_ip[INET_ADDRSTRLEN];

/* 转换客户端IP地址格式 */
inet_ntop(AF_INET, &(sin->sin_addr), client_ip, INET_ADDRSTRLEN);
printf("新客户端连接: %s:%dn", client_ip, ntohs(sin->sin_port));

/* 创建缓冲区事件 */
struct bufferevent *bev = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE);
if (!bev) {
printf("创建缓冲区事件失败n");
return;
}

/* 设置回调函数 */
bufferevent_setcb(bev, client_read_cb, NULL, client_event_cb, NULL);

/* 启用读写事件 */
bufferevent_enable(bev, EV_READ | EV_WRITE);
}

/* 错误处理回调 */
void accept_error_cb(struct evconnlistener *listener, void *ctx) {
struct event_base *base = evconnlistener_get_base(listener);
int err = EVUTIL_SOCKET_ERROR();
printf("监听错误: %sn", evutil_socket_error_to_string(err));

event_base_loopexit(base, NULL);
}

int main(int argc, char **argv) {
struct event_base *base;
struct evconnlistener *listener;
struct sockaddr_in sin;
int port = 9999;

/* 初始化事件基 */
base = event_base_new();
if (!base) {
printf("创建事件基失败n");
return1;
}

/* 配置监听地址 */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(port);

/* 创建监听套接字 */
listener = evconnlistener_new_bind(base, accept_conn_cb, NULL,
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
-1, (struct sockaddr *)&sin, sizeof(sin));
if (!listener) {
printf("创建监听失败n");
event_base_free(base);
return1;
}

/* 设置监听错误回调 */
evconnlistener_set_error_cb(listener, accept_error_cb);

printf("服务器启动,监听端口: %dn", port);

/* 进入事件循环 */
event_base_dispatch(base);

/* 清理资源 */
evconnlistener_free(listener);
event_base_free(base);

return0;
}

编译命令:

gcc -o tcp_server tcp_server.c -I/path/to/libevent/include -L/path/to/libevent/lib -levent -Wl,-rpath=/path/to/libevent/lib

Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。telnet命令可以用来确定远程服务的状态,比如确定远程服务器的某个端口是否能访问。

重要部分:

  • 事件基 (event_base):整个事件处理的核心,管理事件循环和事件分发
  • 连接监听器 (evconnlistener):封装了 TCP 服务器的监听逻辑,简化连接处理
  • 缓冲区事件 (bufferevent):提供了带缓冲区的事件处理,自动管理数据读写
  • 回调函数机制:libevent 采用异步回调模式,避免阻塞式编程

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

本公众号专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,公众号内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!