(十七)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

资金穿透分析

我们把准备好的银行数据导入到软件中,导入具体步骤这里不做详解,大家可以通过“清林情报分析师”公众号,查看操作视频第二节

清林情报分析师 3489

【ES】--Elasticsearch的分词器深度研究

分词器是ik_max_word,会将“龙马家书”拆分为“龙马”、“马家”、“家书”。然后filter配置的是edge_ngram_filter,在上面拆分的token词组基础上,按照edge_ngram_filter规则进一步拆分。从结果看:分词器是keyword,filter支持edge_ngram_filter,字符过滤器支持tsconvert【简繁体】。分词器是keyword,表明是不进行分词,但filtet中edge_ngram_filter是按照布长方式拆分token,所以得到如此结果。

寻梦友的博客 2426

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

【WiFi软件开发】IOCTL和Netlink----用户空间和内核空间交互的两种方式

linux开发中通常会涉及用户空间和内核模块的交互。本文介绍了两种典型的用户空间和内核模块通信方式:ioctl和netlink

liuwe1ye的博客 2348

libevent的bufferevent详解

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

qq_44319972的博客 1202

哨兵1号(Sentinel-1)雷达SAR数据预处理全流程:从下载到精确配准

本文详细介绍了哨兵1号(Sentinel-1)雷达SAR数据从下载到精确配准的全流程预处理方法。内容涵盖SLC与GRD数据选择、ASF平台下载技巧,并重点解析了使用SNAP软件进行几何校正、辐射定标及高精度配准的核心步骤,为InSAR形变监测等应用提供可靠的数据基础。

weixin_29208327的博客 478

Matlab Arduino 硬件支持包安装 MATLAB_Support_Package_for_Arduino_Hardware

Matlab Arduino硬件支持包离线安装

weixin_43283734的博客 2840

libevent转载

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

leopard0825的专栏 322

用OpenCV+ROS实现焊接机器人智能纠偏:线激光视觉的算法调参全流程

本文详细介绍了基于OpenCV和ROS的焊接机器人智能纠偏系统全流程。通过线激光视觉系统实时感知焊缝,重点解析了抗干扰图像预处理、改进的Steger算法提取激光条纹中心线,以及从2D像素到机器人基坐标系的完整坐标变换。该系统为应对焊接飞溅、弧光等复杂工况,实现高精度实时路径纠偏提供了从算法优化到工程集成的完整解决方案。

vodka的博客 159

bufferevent 设置超时

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

Rin的博客 7666

VT-Refine:基于仿真微调的视觉-触觉反馈双臂装配强化学习

本研究提出VT-Refine框架,通过融合真实世界示范、高保真触觉仿真与强化学习,解决高精度双臂装配任务。方法分为两阶段:首先利用少量人类示范数据预训练视觉-触觉扩散策略;随后在数字孪生仿真环境中进行强化学习微调。关键创新包括:开发GPU加速的触觉仿真模块精确模拟压阻式传感器;采用基于点云的多模态表征实现无缝的跨领域迁移。实验表明,该方法在五个双臂装配任务中显著提升性能,触觉反馈使成功率提高40%。研究首次实现仿真环境中的大规模双臂视觉-触觉强化学习及sim-to-real迁移,为接触密集型任务提供了新解决

2506_90492529的博客 1795

VTK API 详解(134):vtkOBJWriter - 写入 OBJ 模型

是 VTK 中用于将数据写入 Wavefront OBJ 文件格式的类。OBJ 格式是广泛支持的 3D 网格模型格式,支持顶点、面和基本几何信息的保存,便于模型在多种三维软件间交换。

yumeiguo的博客 140

简单介绍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万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

【Linux】Libevent库---bufferevent

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

zsyyugong的博客 515

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

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、付费专栏及课程。

余额充值