(十七)bufferevent的管理

Libevent: 缓冲I/O事件bufferevent的封装 介绍Libevent是如何对缓冲I/O事件bufferevent进行封装的,并涉及阅读代码的一些习惯。 阅读详情

前言

在上节中,我们将evbuffers剩余的内容,比如读/写操作进行了剖析。接下来,我们将对bufferevent进行分析,它主要实现了对缓冲区的自动管理。
在本节中,我们先介绍相关结构体以及一些管理操作,相关代码在evbuffer.c以及event.h文件中。

struct bufferevent

该结构体用于管理bufferevent。定义如下:

struct bufferevent {
    struct event_base *ev_base;   //与缓冲区相关联的event_base

    struct event ev_read;  //缓冲区读事件
    struct event ev_write;  //缓冲区写事件

    struct evbuffer *input;    //输入缓冲区
    struct evbuffer *output;  //输出缓冲区

    struct event_watermark wm_read;  //读水位
    struct event_watermark wm_write; //写水位

    evbuffercb readcb;   //缓冲区读回调函数
    evbuffercb writecb;  //缓冲区写回调函数
    everrorcb errorcb;    //发生错误的回调函数
    void *cbarg;        //回调函数的参数

    int timeout_read;   /* in seconds */
    int timeout_write;  /* in seconds */

    short enabled;  //当前启用的事件/* events that are currently enabled */
};

里面又有一个陌生的结构体,struct event_watermark,它也在event.h中定义:

struct event_watermark {
        size_t low;   //低水位   
        size_t high;  //高水位
}

它之所以可以自动管理缓冲区就是因为水位以及相应回调函数的设置。一共有4个水位,分别是读取低水位、读取高水位、写入低水位、写入高水位,它们的作用分别如下:

  1. 读取低水位:当读取操作使输入缓冲区的数据大小超过或等于该水位时,就会调用回调函数。而读取低水位的默认值是0,所以每一次进行读取操作都会导致回调函数被调用。
  2. 读取高水位:它相当于一个警戒线,当输入缓冲区的数据量达到该水位,则停止数据的读取,直到水位回退。它的默认值是无限。
  3. 写入低水位:写入操作使得输出缓冲区的数据量低于或等于该水位时,会调用相关的回调函数。默认值是0,所以只有当输出缓冲区为空时才会调用回调函数。
  4. 写入高水位:bufferevent没有直接使用这个水位。它在bufferevent用作另外一个bufferevent的底层传输端口时有特殊意义。

接下来了解这些基本信息,我们先来看看初始化操作。

新建一个bufferevent

struct bufferevent *
bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb,
    everrorcb errorcb, void *cbarg)
{
    struct bufferevent *bufev;
    //申请内存
    if ((bufev = calloc(1, sizeof(struct bufferevent))) == NULL)
        return (NULL);
    //初始化输入缓冲区
    if ((bufev->input = evbuffer_new()) == NULL) {
        free(bufev);
        return (NULL);
    }
    //初始化输出缓冲区
    if ((bufev->output = evbuffer_new()) == NULL) {
        evbuffer_free(bufev->input);
        free(bufev);
        return (NULL);
    }
    /* 初始化缓冲区读/写事件(设置fd、事件类型、回调函数、参数等成员值) */
    event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
    event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
    //设置bufferevent中的回调函数及参数
    bufferevent_setcb(bufev, readcb, writecb, errorcb, cbarg);

    /*
     * Set to EV_WRITE so that using bufferevent_write is going to
     * trigger a callback.  Reading needs to be explicitly enabled
     * because otherwise no data will be available.
     */
    //自动启用写事件,读事件需要有数据可读时才被启用
    bufev->enabled = EV_WRITE;

    return (bufev);
}

该函数无需多说什么,而对应的bufferevent_free主要就是几个释放资源的操作,如下:

/* Closing the file descriptor is the responsibility of the caller */

void
bufferevent_free(struct bufferevent *bufev)
{
    event_del(&bufev->ev_read);
    event_del(&bufev->ev_write);

    evbuffer_free(bufev->input);
    evbuffer_free(bufev->output);

    free(bufev);
}

接下来便是一些设置相关成员的函数,比如注册到event_base还有设置事件优先级、回调函数等。

将读/写事件注册到event_base上

这个操作主要由bufferevent_base_set完成:

int
bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
{
    int res;

    bufev->ev_base = base;

    res = event_base_set(base, &bufev->ev_read);
    if (res == -1)
        return (res);

    res = event_base_set(base, &bufev->ev_write);
    return (res);
}

如果对event_base_set函数的作用有所疑惑,建议重新翻到第6小节看看。

设置水位线

/*
 * Sets the water marks
 */
void
bufferevent_setwatermark(struct bufferevent *bufev, short events,
    size_t lowmark, size_t highmark)
{
    /* 根据事件的类型来设置相应的水位 */
    if (events & EV_READ) {
        bufev->wm_read.low = lowmark;
        bufev->wm_read.high = highmark;
    }

    if (events & EV_WRITE) {
        bufev->wm_write.low = lowmark;
        bufev->wm_write.high = highmark;
    }

    /* If the watermarks changed then see if we should call read again */
    bufferevent_read_pressure_cb(bufev->input,
        0, EVBUFFER_LENGTH(bufev->input), bufev);
}

若水位发生了变化,可能会导致读事件再次发生。

void
bufferevent_read_pressure_cb(struct evbuffer *buf, size_t old, size_t now,  
    void *arg) {
    struct bufferevent *bufev = arg;
    /*
     * If we are below the watermark then reschedule reading if it's
     * still enabled.
     */
    //如果高水位线为0,或者当前缓冲区大小小于高水位线并且当读操作启用时,证明还可以进行读,则重新调度读事件
    if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) {  
        evbuffer_setcb(buf, NULL, NULL); //把该缓冲区的回调函数设为空

        if (bufev->enabled & EV_READ)
            bufferevent_add(&bufev->ev_read, bufev->timeout_read);  //让这个事件过timeout_read再读
    }                                       
}

设置优先级

int
bufferevent_priority_set(struct bufferevent *bufev, int priority)
{
    if (event_priority_set(&bufev->ev_read, priority) == -1)   
        return (-1);
    if (event_priority_set(&bufev->ev_write, priority) == -1)
        return (-1);

    return (0);
}

里面调用的主要函数也是我们以前讲过的。

设置定时

void
bufferevent_settimeout(struct bufferevent *bufev,
    int timeout_read, int timeout_write) {
    bufev->timeout_read = timeout_read;
    bufev->timeout_write = timeout_write;

    /* 检测时间是否处于未决状态
     * 如果是,则注册该定时事件
     */
    if (event_pending(&bufev->ev_read, EV_READ, NULL))
        bufferevent_add(&bufev->ev_read, timeout_read);
    if (event_pending(&bufev->ev_write, EV_WRITE, NULL))
        bufferevent_add(&bufev->ev_write, timeout_write);
}  

注册事件

static int
bufferevent_add(struct event *ev, int timeout)
{
    struct timeval tv, *ptv = NULL;

    if (timeout) {
        evutil_timerclear(&tv); //清空tv结构体
        tv.tv_sec = timeout;
        ptv = &tv;
    }

    //注册事件到event_base上
    return (event_add(ev, ptv));  
}

注销事件

int
bufferevent_disable(struct bufferevent *bufev, short event)
{
    if (event & EV_READ) {
        if (event_del(&bufev->ev_read) == -1)
            return (-1);
    }
    if (event & EV_WRITE) {
        if (event_del(&bufev->ev_write) == -1)
            return (-1);
    }

    bufev->enabled &= ~event;
    return (0);
}

注册事件,根据事件类型并设置enabled

int
bufferevent_enable(struct bufferevent *bufev, short event)
{
    if (event & EV_READ) {
        if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1)
            return (-1);
    }
    if (event & EV_WRITE) {
        if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1)
            return (-1);
    }

    bufev->enabled |= event;
    return (0);
}

小结

本节主要介绍了bufferevent水位线的设置,以及它主要的逻辑,这个和之前讲的事件相关的有很大的联系。当事件被激活时,首先调用的是bufferevent_readcb或bufferevent_writecb,然后bufferevent_readcb或bufferevent_writecb中才调用用户自己设置的回调函数。
在下一节中,我们将主要分析这两个函数,以及剩余的读/写函数。

Libevent源码分析-----bufferevent工作流程探究 和之前的《Libevent工作流程探究》一样,这里也是用一个例子来探究bufferevent的工作流程。具体的例子可以参考《Libevent客户端例子》,这里就不列出了。其实要做的例子也就是bufferevent_socket_new、bufferevent_setcb、bufferevent_enable这几个函数。 因为本文会用到《Libevent工作流程探究》中提到的说法,比如将一个eve 阅读详情

相关推荐

开源事件通知库libevent及网络连接管理模块bufferevent详解

开源事件通知库libevent及网络连接管理模块bufferevent详解

dvlinker的技术专栏 1万+

使用libevent编写linux服务

一 libevent简介 libevent是一个支持Windows、linux和bsd等平台的网络事件驱动程序库。它支持多种I/O服用机制,按照优先级从高到低依次为:evport、kqueue、epoll、devpoll、rtsig、poll、select。它可根据操作系统,按照优先级从高到底自主选择驱动。      用户可以通过http://www.monkey.org/~provo

冰枫的随笔 1732

OpenWrt路由器专用轻量xfrpc客户端源码:纯C实现,支持MIPS/ARM交叉编译

专为OpenWrt嵌入式设备打造的xfrpc内网穿透客户端源码包,完全用标准C语言编写,不依赖glibc或复杂运行时环境,编译后二进制体积小、内存占用低,适配MT7621、BCM47XX等中低端路由器硬件。源码包含完整的FRP协议通信模块(TCP/UDP代理、TCP重定向、FTP代理)、JSON配置解析(基于-c精简组件)、SSL/TLS加密传输(集成OpenSSL bufferevent封装)、zlib压缩支持(deflate/inflate/crc32),以及事件驱动网络层(event.c/buffer

y9z0a1b的博客 251

libevent+bufferevent总结

libevent+bufferevent总结 1 学习参考网址 libevent学习网址:http://blog.youkuaiyun.com/feitianxuxue/article/details/9372535 http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html http://www.cppblog.com/mysilen...

weixin_33935777的博客 114

Cursor Cloud Agent:云原生编程工作流的底层重构

编程工作流正从本地计算范式转向云原生执行范式。Cloud Agent 本质是将代码理解、生成、执行与调试等核心能力下沉至隔离、可控、按需分配的云端虚拟机,通过 Firecracker 微虚拟机实现亚秒级启动,并依托上下文快照、环境镜像化和内核级沙箱保障一致性、算力弹性与数据安全。这一范式突破了传统本地 AI 编程助手在环境依赖、调试能力与企业合规上的根本局限,使 IDE 从编辑工具升维为分布式开发指挥中心。本文深入解析其运行机制与工程落地实践。

weixin_34354173的博客 337

【FnOS飞牛云 | NAS存储】旧电脑不吃灰,手把手教你搭建完全属于自己的私人网盘

打造属于自己的NAS私人网盘,亲测有效,值得一试

木子Linux的博客世界 9416

libevent学习——buffevent事件及低水位高水位设置

设置buffevent_cb的函数原型 void bufferevent_setcb(struct bufferevent *bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg); 注意event_cb函数指针和readcb是不一样的,event_cb多了一个short参数,和之前学习的event事件的回调函数类似 typedef

dxgzg的博客 2095

SAP LTMC实战指南:物料主数据高效导入全解析

本文详细解析了SAP LTMC工具在物料主数据高效导入中的实战应用,包括工具选择、项目搭建、模板定制、数据导入全流程及常见问题解决方案。重点介绍了LTMC的预置模板、LTMOM灵活配置、数据校验机制等核心功能,帮助用户快速掌握SAP数据迁移技巧,提升工作效率。

weixin_33738555的博客 435

libevent的bufferevent详解

详细说明了bufferevent的功能和常用函数

qq_44319972的博客 1202

北航机器学习期末考试试题2020年春

北航机器学习期末考试试题2020春 看csdn上试题收费,积分还挺高,本着共享的理念,把2020春季ML考试的试题公开,若侵权,立删 前8道题10分,第9题20分 决策树采用ID3算法 对宇宙星球是否适合生存分类 SVM的原理;软间隔、硬间隔;以及对非线性样本点分类 集成学习的原理,以及及串行boosting以及bagging的简单概括 K-means与混合高斯模型的异同以及EM算法的原理,如何计算 马尔可夫随机场最大团;马尔可夫随机场的联合概率分布(势函数表示),贝叶斯网络联合概率分布 PCA主成分基于

qq_43343919的博客 5417

单线激光雷达的工作原理

单线激光雷达通过单一激光束的水平扫描和时间 / 相位测量,实现二维环境的距离感知,是低成本二维导航的核心传感器。尽管其无法直接提供三维信息,但其可靠性和经济性使其在消费级和工业级场景中广泛应用。随着技术发展,部分单线雷达通过振动镜或 MEMS 微振镜实现微小角度偏转,可近似模拟多线扫描效果,进一步拓展了应用边界。

谢谢大家的关注和点赞!这里只有纯纯的知识干货,没有一句废话。希望能实实在在帮到大家~要是觉得有用,别忘了给我点支持哟,你 1859

libevent转载

libevent   2011-07-06 09:35:32|  分类: 默认分类 |  标签:libevent  c++框架  |字号 订阅 很多时候,除了响应事件之外,应用还希望做一定的数据缓冲。比如说,写入数据的时候,通常的运行模式是: l 决定要向连接写入一些数据,把数据放入到缓冲区中 l 等待连接可以写入 l 写入尽量多的数据 l 记住写入了...

leopard0825的专栏 322

Android 系统状态栏中实现高斯模糊背景

至此,我们已经完成了在 Android 系统的 SystemUI 中实现高斯模糊背景的过程。通过以上的布局和代码修改,我们可以在状态栏中看到具有高斯模糊效果的背景。同时,为了在不同版本的 Android 系统上适配高斯模糊效果,可能需要进行一些额外的代码调整和兼容性处理。希望本文能够帮助你理解如何在 Android 系统的 SystemUI 中实现高斯模糊背景,并通过提供的源代码进行相应的开发和调试。首先,我们需要在 SystemUI 的布局文件中添加一个用于展示高斯模糊背景的视图。属性来开启模糊效果。

CyberSparkZ的博客 870

bufferevent 设置超时

用bufferevent 有一段时间了,自认为还蛮熟悉的。后来因为一项业务,需要把心跳的频率控制转到服务端来。 我们考虑两种情况,一是服务端只响应心跳,不做断开操作,断开操作由客户端收不到响应而发起;二是客户端定期发送心跳,服务端响应心跳,若一定时间未有心跳则断开客户端。或许还有两种的结合,两边都判断超时都断开。 最开始我们选择的是第一种场景,只收心跳且服务端不响应心跳,这样可以减少服务端

Rin的博客 7666

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

简单介绍libevent快速上手

http://blog.chukong-inc.com/index.php/2012/02/26/%E7%AE%80%E5%8D%95%E4%BB%8B%E7%BB%8Dlibevent%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B/ 简介 libevent是一个事件出发的网络库,使用与 windows,linux,bad, mac os 等的高性能跨平台

chengfangang的专栏 909

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

处理大并发之五 使用libevent利器bufferevent

处理大并发之五 使用lievent利器bufferevent          首先来翻译一段文章          你可能注意到随着我们代码变得越来越高效,程序也变得更加复杂。当我们产生一个进程的时候,我们没有必要为每一个链接管理一个buffer,我们只需要每个处理独立栈分配缓冲区就可以了。在读和写的时候,我们不必明确的跟踪每一个socket,这在我们的代码里是一个暗示,我们没有必要定义一个

feitianxuxue的专栏 4万+

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

【Linux】Libevent库---bufferevent

不能先创建bufferevent,因为需要封装进去的是cfd,而不是lfd。 lfd创建的过程应该是直接封装在evconnlister_new_bind函数中的,外部不可见,因为根本不需要我们操作lfd。 创建buffrtevent事件对象时,需要有一个客户端对应的文件描述符,而这个文件描述符只有在先监听了后才会有。

zsyyugong的博客 515

bufferevent有关介绍与使用

bufferevent有关介绍与使用

qq_46312211的博客 2670

bufferevent

转载请注明出处:http://blog.youkuaiyun.com/luotuo44/article/details/39344743 和之前的《Libevent工作流程探究》一样,这里也是用一个例子来探究bufferevent的工作流程。具体的例子可以参考《Libevent使用例子,从简单到复杂》,这里就不列出了。其实要做的例子也就是bufferevent_socket_new、bufferevent_setcb、bufferevent_enable这几个函数。 因为本文会用到《Libev...

qixiang2013的专栏 613

libevent中bufferevent事件及常用的API函数

bufferevent实际上也是一个event,只不过比普通的event高级,他的内部有两个缓冲区,以及一个文件描述符(网络套接字)。一个网络套接字有读写两个缓冲区,bufferevent同样也带有两个缓冲区。所以有四个缓冲区。

luosuss的博客 1669

libevent库学习(2)

本次重点介绍bufferevent。很多时候,除了响应事件之外,应用还希望做一定的数据缓冲。比如说,写入数据的时候,通常的运行模式是(1)决定要向连接写入一些数据,把数据放入到缓冲区中(2)等待连接可以写入(3)写入尽量多的数据(4)记住写入了多少数据,如果还有更多数据要写入,等待连接再次可以写入这种缓冲lO模式很通用,libevent为此提供了一种通用机制,即bufferevent。带有buf的事件对象有两个缓冲区,一个读缓冲区,一个写缓冲区;】这一节的常规事件来记忆。...

StudyWinter的博客 1280

(十八)bufferevent的读写回调函数及对外接口

前言在上一节中,我们介绍了bufferevent实现自动管理的基本思想(水位线机制),在本小节中,我们将介绍bufferevent_readcb、bufferevent_writecb等函数,了解它工作的全过程。bufferevent_readcbstatic void bufferevent_readcb(int fd, short event, void *arg) { struct

Move_now的博客 6073

linux入门到精通-第二十章-bufferevent(开源高性能事件通知库)

一般通过libevent进行网络编程,都是将一个socket的fd与一个event进行绑定,并自行维护一个buffer用于存储从socket上接收的数据,同时可能也用于待发送数据的缓存。然后通过可读可写事件从socket上收取数据写入缓存并进行相应处理,或者将缓存中的数据通过socket发送。libevent为这种带缓存的IO模式提供了一种通用的机制,那就是bufferevent。

Blueeyedboy521的博客 1251

Libevent之bufferevent详解

#简介 bufferevent专门为封装成带有缓冲区的socket套接字。当有数据到来时,我们只需要在回调函数里面通过封装函数读取数据即可,根本不需要自己处理一些细节,以及缓存的问题。 bufferevent其实也就是在的基础上再进行一层封装,其本质还是离不开event和event_base,从bufferevent的结构体就可以看到这一点。 bufferevent结构体中有两个event,分别用来监听同一个fd的可读事件和可写事件。为什么不用一个event同时监听可读和可写呢?这是因为监听可写是困难的,下

一个菜鸟的博客 1万+
上一篇: (十六)evbuffers缓冲区(下)
下一篇: (十八)bufferevent的读写回调函数及对外接口
UKey_
博客等级 码龄10年 258粉丝 186原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值