Libevent TCP开发指南

news2025/4/5 23:07:20

一、概念

Libevent 提供了高效的 TCP 网络编程接口,使开发者能够轻松构建高性能的 TCP 服务器和客户端。本指南将详细介绍如何使用 Libevent 进行 TCP 网络开发。

核心组件

  1. 事件基 (event_base) - 事件处理的核心结构

  2. 事件 (event) - 表示单个事件

  3. 缓冲区事件 (bufferevent) - 带缓冲的 I/O 事件

  4. 监听器 (evconnlistener) - TCP 连接监听器

  5. 缓冲区 (evbuffer) - 高效的数据缓冲区

常用 API

事件基

  • event_base_new() - 创建新的事件基

  • event_base_free() - 释放事件基

  • event_base_dispatch() - 开始事件循环

  • event_base_loopexit() - 退出事件循环

事件

  • event_new() - 创建新事件

  • event_free() - 释放事件

  • event_add() - 添加事件到事件基

  • event_del() - 从事件基中删除事件

缓冲区事件

  • bufferevent_socket_new() - 创建新的缓冲区事件

  • bufferevent_setcb() - 设置回调函数

  • bufferevent_enable() - 启用事件

  • bufferevent_write() - 写入数据

  • bufferevent_read() - 读取数据

event与bufferevent

普通事件(event)‌:基础事件类型,用于监听文件描述符的可读/可写状态、信号、定时器等单一事件触发。用户需手动管理I/O操作和缓冲区的数据读写‌。比如:监听socket的可读事件后,需自行调用read()读取数据并处理粘包/分包问题‌。
缓冲区事件(bufferevent):高级封装的事件类型,内置输入/输出缓冲区(evbuffer结构体),自动处理底层I/O的读写操作和数据缓冲。用户只需通过回调函数处理已就绪的数据‌。比如:收到数据时自动填充输入缓冲区,触发读回调;用户调用bufferevent_write()时,数据先写入输出缓冲区,由libevent自动发送‌。

特性 普通事件(event) 缓冲区事件(bufferevent)
数据缓冲 需用户手动管理 内置输入/输出缓冲区,自动管理
水位控制 不支持 支持设置高/低水位标记‌
适用场景 信号、定时器、低层I/O控制 流式网络通信(如TCP服务)
多线程支持 需额外同步机制 提供线程安全的缓冲区操作接口‌

二、TCP 服务器开发

1. 基本服务器框架

#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <arpa/inet.h>

// 定义回调函数
void read_cb(struct bufferevent *bev, void *ctx);
void event_cb(struct bufferevent *bev, short events, void *ctx);
void accept_conn_cb(struct evconnlistener *listener, 
                   evutil_socket_t fd,
                   struct sockaddr *address, 
                   int socklen,
                   void *ctx);

int main() {
    // 1. 创建事件基
    struct event_base *base = event_base_new();
    if (!base) {
        fprintf(stderr, "Could not initialize libevent!\n");
        return 1;
    }

    // 2. 配置服务器地址
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8080);  // 监听8080端口
    sin.sin_addr.s_addr = htonl(INADDR_ANY);  // 监听所有接口

    // 3. 创建监听器
    struct evconnlistener *listener = evconnlistener_new_bind(
        base, accept_conn_cb, NULL,
        LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1,
        (struct sockaddr*)&sin, sizeof(sin));
    
    if (!listener) {
        fprintf(stderr, "Could not create a listener!\n");
        return 1;
    }

    // 4. 启动事件循环
    event_base_dispatch(base);

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

    return 0;
}

2. 连接接受回调

void accept_conn_cb(struct evconnlistener *listener, 
                   evutil_socket_t fd,
                   struct sockaddr *address, 
                   int socklen,
                   void *ctx) {
    struct event_base *base = evconnlistener_get_base(listener);
    
    // 为新的客户端连接创建bufferevent
    struct bufferevent *bev = bufferevent_socket_new(
        base, fd, BEV_OPT_CLOSE_ON_FREE);
    
    if (!bev) {
        fprintf(stderr, "Error constructing bufferevent!");
        event_base_loopbreak(base);
        return;
    }

    // 设置回调函数
    bufferevent_setcb(bev, read_cb, NULL, event_cb, NULL);
    
    // 启用读写事件
    bufferevent_enable(bev, EV_READ | EV_WRITE);
    
    // 可选: 设置水位标记
    bufferevent_setwatermark(bev, EV_READ, 0, 4096); // 最大读取4096字节
}

3. 数据读取回调

void read_cb(struct bufferevent *bev, void *ctx) {
    struct evbuffer *input = bufferevent_get_input(bev);
    size_t len = evbuffer_get_length(input);
    
    // 分配缓冲区
    unsigned char *buffer = malloc(len + 1);
    
    // 从输入缓冲区读取数据
    bufferevent_read(bev, buffer, len);
    buffer[len] = '\0';
    
    printf("Received %zu bytes: %s\n", len, buffer);
    
    // 回显数据
    bufferevent_write(bev, buffer, len);
    
    free(buffer);
}

4. 事件处理回调

void event_cb(struct bufferevent *bev, short events, void *ctx)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2328828.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java基础:面向对象进阶(二)

01-static static修饰成员方法 static注意事项&#xff08;3种&#xff09; static应用知识&#xff1a;代码块 static应用知识&#xff1a;单列模式 02-面向对象三大特征之二&#xff1a;继承 什么是继承&#xff1f; 使用继承有啥好处? 权限修饰符 单继承、Object类 方法重…

ttkbootstrap 实现日期选择器, 开始和结束时间

ttkbootstrap 实现日期选择器&#xff0c; 开始和结束时间 1. 展示 2. 打印 3. 源码 from datetime import datetime import ttkbootstrap as ttkclass DateTimeEntryStart(ttk.Frame):def __init__(self, masterNone, **kwargs):super().__init__(master, **kwargs)self.dat…

Vulnhub-PrinkysPalacev3

Vulnhub-PrinkysPalacev3 1、主机发现 arp-scan -l 扫描同网段 2、端口扫描 nmap -sS -sV 192.168.66.185 nmap -sS -A -T4 -p- 192.168.66.185 nmap --scriptvuln 192.168.66.185 PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 2.0.8 or later 5555/tcp o…

matlab从pytorch中导入LeNet-5网络框架

文章目录 一、Pytorch的LeNet-5网络准备二、保存用于导入matlab的model三、导入matlab四、用matlab训练这个导入的网络 这里演示从pytorch的LeNet-5网络导入到matlab中进行训练用。 一、Pytorch的LeNet-5网络准备 根据LeNet-5的结构图&#xff0c;我们可以写如下结构 import…

Spring Boot向Vue发送消息通过WebSocket实现通信

注意&#xff1a;如果后端有contextPath&#xff0c;如/app&#xff0c;那么前端访问的url就是ip:port/app/ws 后端实现步骤 添加Spring Boot WebSocket依赖配置WebSocket端点和消息代理创建控制器&#xff0c;使用SimpMessagingTemplate发送消息 前端实现步骤 安装sockjs-…

网络编程—Socket套接字(UDP)

上篇文章&#xff1a; 网络编程—网络概念https://blog.csdn.net/sniper_fandc/article/details/146923380?fromshareblogdetail&sharetypeblogdetail&sharerId146923380&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目录 1 概念 2 Soc…

视频设备轨迹回放平台EasyCVR综合智能化,搭建运动场体育赛事直播方案

一、背景 随着5G技术的发展&#xff0c;体育赛事直播迎来了新的高峰。无论是NBA、西甲、英超、德甲、意甲、中超还是CBA等热门赛事&#xff0c;都是值得记录和回放的精彩瞬间。对于体育迷来说&#xff0c;选择观看的平台众多&#xff0c;但是作为运营者&#xff0c;搭建一套体…

AIGC实战——CycleGAN详解与实现

AIGC实战——CycleGAN详解与实现 0. 前言1. CycleGAN 基本原理2. CycleGAN 模型分析3. 实现 CycleGAN小结系列链接 0. 前言 CycleGAN 是一种用于图像转换的生成对抗网络(Generative Adversarial Network, GAN)&#xff0c;可以在不需要配对数据的情况下将一种风格的图像转换成…

VS2022远程调试Linux程序

一、 1、VS2022安装参考 VS Studio2022安装教程&#xff08;保姆级教程&#xff09;_visual studio 2022-CSDN博客 注意&#xff1a;勾选的时候&#xff0c;要勾选下方的选项&#xff0c;才能调试Linux环境下运行的程序&#xff01; 2、VS2022远程调试Linux程序测试 原文参…

345-java人事档案管理系统的设计与实现

345-java人事档案管理系统的设计与实现 项目概述 本项目为基于Java语言的人事档案管理系统&#xff0c;旨在帮助企事业单位高效管理员工档案信息&#xff0c;实现档案的电子化、自动化管理。系统涵盖了员工信息的录入、查询、修改、删除等功能&#xff0c;同时具备权限控制和…

【Linux系统编程】进程概念,进程状态

目录 一&#xff0c;操作系统&#xff08;Operator System&#xff09; 1-1概念 1-2设计操作系统的目的 1-3核心功能 1-4系统调用和库函数概念 二&#xff0c;进程&#xff08;Process&#xff09; 2-1进程概念与基本操作 2-2task_struct结构体内容 2-3查看进程 2-4通…

优选算法的妙思之流:分治——快排专题

专栏&#xff1a;算法的魔法世界 个人主页&#xff1a;手握风云 目录 一、快速排序 二、例题讲解 2.1. 颜色分类 2.2. 排序数组 2.3. 数组中的第K个最大元素 2.4. 库存管理 III 一、快速排序 分治&#xff0c;简单理解为“分而治之”&#xff0c;将一个大问题划分为若干个…

wx206基于ssm+vue+uniapp的优购电商小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

React编程高级主题:错误处理(Error Handling)

文章目录 **5.2 错误处理&#xff08;Error Handling&#xff09;概述****5.2.1 onErrorReturn / onErrorResume&#xff08;错误回退&#xff09;****1. onErrorReturn&#xff1a;提供默认值****2. onErrorResume&#xff1a;切换备用数据流** **5.2.2 retry / retryWhen&…

ubuntu20.04升级成ubuntu22.04

命令行 sudo do-release-upgrade 我是按提示输入y确认操作&#xff0c;也可以遇到配置文件冲突时建议选择N保留当前配置

SpringCloud(25)——Stream介绍

1.场景描述 当我们的分布式系统建设到一定程度了&#xff0c;或者服务间是通过异步请求来通讯的&#xff0c;那么我们避免不了使用MQ来解决问题。 假如公司内部进行了业务合并或者整合&#xff0c;需要服务A和服务B通过MQ的方式进行消息传递&#xff0c;而服务A用的是RabbitMQ&…

centos8上实现lvs集群负载均衡dr模式

1.前言 个人备忘笔记&#xff0c;欢迎探讨。 centos8上实现lvs集群负载均衡nat模式 centos8上实现lvs集群负载均衡dr模式 之前写过一篇lvs-nat模式。实验起来相对顺利。dr模式最大特点是响应报文不经调度器&#xff0c;而是直接返回客户机。 dr模式分同网段和不同网段。同…

uniapp如何接入星火大模型

写在前面&#xff1a;最近的ai是真的火啊&#xff0c;琢磨了一下&#xff0c;弄个uniappx的版本开发个东西玩一下&#xff0c;想了想不知道放啥内容&#xff0c;突然觉得deepseek可以接入&#xff0c;好家伙&#xff0c;一对接以后发现这是个付费的玩意&#xff0c;我穷&#x…

MySQL vs MSSQL 对比

在企业数据库管理系统中&#xff0c;MySQL 和 Microsoft SQL Server&#xff08;MSSQL&#xff09;是最受欢迎的两大选择。MySQL 是一款开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;由 MySQL AB 开发&#xff0c;现归属于 Oracle 公司。而 MSSQL 是微…

python基础-10-组织文件

文章目录 【README】【10】组织文件&#xff08;复制移动删除重命名&#xff09;【10.1】shutil模块(shell工具)【10.1.1】复制文件和文件夹【10.1.1.1】复制文件夹及其下文件-shutil.copytree 【10.1.2】文件和文件夹的移动与重命名【10.1.3】永久删除文件和文件夹【10.1.4】用…