bufferevent,带buffer的event

struct bufferevent {struct event_base *ev_base;const struct bufferevent_ops *be_ops;   // backendstruct event ev_read;               // 读事件struct event ev_write;              // 写事件struct evbuffer *input;             // 读缓冲struct evbuffer *output;            // 写缓冲
    bufferevent_data_cb readcb;         // 读事件回调bufferevent_data_cb writecb;        // 写事件回调bufferevent_event_cb errorcb;       // error回调void *cbarg;                        // 回调函数参数struct event_watermark wm_read;struct event_watermark wm_write;struct timeval timeout_read;struct timeval timeout_write;short enabled;
};

下面简单分析bufferevent相关函数(示例DEMO)

bufferevent_socket_new

struct bufferevent *
bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,int options)
{struct bufferevent_private *bufev_p;struct bufferevent *bufev;#ifdef WIN32if (base && event_base_get_iocp(base))return bufferevent_async_new(base, fd, options);
#endifif ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL)return NULL;if (bufferevent_init_common(bufev_p, base, &bufferevent_ops_socket,options) < 0) {mm_free(bufev_p);return NULL;}bufev = &bufev_p->bev;evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD);event_assign(&bufev->ev_read, bufev->ev_base, fd,EV_READ|EV_PERSIST, bufferevent_readcb, bufev);event_assign(&bufev->ev_write, bufev->ev_base, fd,EV_WRITE|EV_PERSIST, bufferevent_writecb, bufev);evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev);evbuffer_freeze(bufev->input, 0);evbuffer_freeze(bufev->output, 1);return bufev;
}

函数做了4件事:

  1. 设置backend: bufferevent_ops_socket
  2. 设置fd的读事件回调: bufferevent_readcb
  3. 设置fd的写事件回调: bufferevent_writecb
  4. 设置输出缓冲区的回调: bufferevent_socket_outbuf_cb

backend结构如下:

const struct bufferevent_ops bufferevent_ops_socket = {"socket",evutil_offsetof(struct bufferevent_private, bev),be_socket_enable,be_socket_disable,be_socket_destruct,be_socket_adj_timeouts,be_socket_flush,be_socket_ctrl,
};

bufferevent_setcb

void
bufferevent_setcb(struct bufferevent *bufev,bufferevent_data_cb readcb, bufferevent_data_cb writecb,bufferevent_event_cb eventcb, void *cbarg)
{BEV_LOCK(bufev);bufev->readcb = readcb;bufev->writecb = writecb;bufev->errorcb = eventcb;bufev->cbarg = cbarg;BEV_UNLOCK(bufev);
}

该函数主要设置用户回调函数。

bufferevent_enable

int
bufferevent_enable(struct bufferevent *bufev, short event)
{struct bufferevent_private *bufev_private =EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);short impl_events = event;int r = 0;_bufferevent_incref_and_lock(bufev);if (bufev_private->read_suspended)impl_events &= ~EV_READ;if (bufev_private->write_suspended)impl_events &= ~EV_WRITE;bufev->enabled |= event;if (impl_events && bufev->be_ops->enable(bufev, impl_events) < 0)r = -1;_bufferevent_decref_and_unlock(bufev);return r;
}static int
be_socket_enable(struct bufferevent *bufev, short event)
{if (event & EV_READ) {if (be_socket_add(&bufev->ev_read,&bufev->timeout_read) == -1)return -1;}if (event & EV_WRITE) {if (be_socket_add(&bufev->ev_write,&bufev->timeout_write) == -1)return -1;}return 0;
}#define be_socket_add(ev, t)            \_bufferevent_add_event((ev), (t))int
_bufferevent_add_event(struct event *ev, const struct timeval *tv)
{if (tv->tv_sec == 0 && tv->tv_usec == 0)return event_add(ev, NULL);elsereturn event_add(ev, tv);
}

该函数将fd加入到epoll中。

事件流程

当fd上有读事件发生时,首先调用bufferevent_readcb。

static void
bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
{struct bufferevent *bufev = arg;struct bufferevent_private *bufev_p =EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);struct evbuffer *input;int res = 0;short what = BEV_EVENT_READING;ev_ssize_t howmuch = -1, readmax=-1;_bufferevent_incref_and_lock(bufev);if (event == EV_TIMEOUT) {/* Note that we only check for event==EV_TIMEOUT. If* event==EV_TIMEOUT|EV_READ, we can safely ignore the* timeout, since a read has occurred */what |= BEV_EVENT_TIMEOUT;goto error;}input = bufev->input;/** If we have a high watermark configured then we don't want to* read more data than would make us reach the watermark.*/if (bufev->wm_read.high != 0) {howmuch = bufev->wm_read.high - evbuffer_get_length(input);/* we somehow lowered the watermark, stop reading */if (howmuch <= 0) {bufferevent_wm_suspend_read(bufev);goto done;}}readmax = _bufferevent_get_read_max(bufev_p);if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited"* uglifies this code. XXXX */howmuch = readmax;if (bufev_p->read_suspended)goto done;evbuffer_unfreeze(input, 0);res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */evbuffer_freeze(input, 0);if (res == -1) {int err = evutil_socket_geterror(fd);if (EVUTIL_ERR_RW_RETRIABLE(err))goto reschedule;/* error case */what |= BEV_EVENT_ERROR;} else if (res == 0) {/* eof case */what |= BEV_EVENT_EOF;}if (res <= 0)goto error;_bufferevent_decrement_read_buckets(bufev_p, res);/* Invoke the user callback - must always be called last */if (evbuffer_get_length(input) >= bufev->wm_read.low)_bufferevent_run_readcb(bufev);goto done;reschedule:goto done;error:bufferevent_disable(bufev, EV_READ);_bufferevent_run_eventcb(bufev, what);done:_bufferevent_decref_and_unlock(bufev);
}

通过evbuffer_read(内部调用recv),将fd上的数据读入输入缓冲input中。

通过_bufferevent_run_readcb调用用户回调函数

(如果出错,通过_bufferevent_run_eventcb调用errorcb)

void
_bufferevent_run_readcb(struct bufferevent *bufev)
{/* Requires that we hold the lock and a reference */struct bufferevent_private *p =EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);if (bufev->readcb == NULL)return;if (p->options & BEV_OPT_DEFER_CALLBACKS) {p->readcb_pending = 1;if (!p->deferred.queued)SCHEDULE_DEFERRED(p);} else {bufev->readcb(bufev, bufev->cbarg);}
}

在用户回调函数中,可以通过 bufferevent_read 取出输入缓冲input中的数据。

size_t
bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
{return (evbuffer_remove(bufev->input, data, size));
}/* Reads data from an event buffer and drains the bytes read */
int
evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
{ev_ssize_t n;EVBUFFER_LOCK(buf);n = evbuffer_copyout(buf, data_out, datlen);if (n > 0) {if (evbuffer_drain(buf, n)<0)n = -1;}EVBUFFER_UNLOCK(buf);return (int)n;
}

参考资料:

Libevent源码分析-----evbuffer结构与基本操作

Libevent源码分析-----更多evbuffer操作函数

转载于:https://www.cnblogs.com/gattaca/p/7827479.html

libevent(九)bufferevent相关推荐

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

    理大并发之五 使用libevent利器bufferevent 首先来翻译一段文章 你可能注意到随着我们代码变得越来越高效,程序也变得更加复杂.当我们产生一个进程的时候,我们没有必要为每一个链接管理一个 ...

  2. libevent库bufferevent事件实现socket通信

    一.基础API 1. 添加 bufferevent 事件 struct bufferevent *bufferevent_socket_new(struct event_base *base, evu ...

  3. libevent详解与实践

    文章目录 前言 编译 linux ARM 生成库 概述 标准用法 库设置 创建event base 事件通知 调度事件. I/O缓冲区 计时器 异步DNS解析 事件驱动的HTTP服务器 RPC服务器和 ...

  4. libevent(1)

    很多时候,除了响应事件之外,应用还希望做一定的数据缓冲.比如说,写入数据的时候,通常的运行模式是: l 决定要向连接写入一些数据,把数据放入到缓冲区中 l 等待连接可以写入 l 写入尽量多的数据 l  ...

  5. 网络库libevent、libev、libuv、libhv对比

    网络库libevent.libev.libuv对比_小麒麟的成长之路-CSDN博客_libevent libuv Libevent.libev.libuv三个网络库,都是c语言实现的异步事件库Asyn ...

  6. Linux c 开发 - libevent

    目录 一.event_base 1. 创建event_base 2. 查看IO模型 3. 销毁event_base 4. 事件循环 event loop 5. event_base的例子 二.even ...

  7. libevent与libev简介

    libevent和libev都是c语言实现的异步事件库,主要封装了三个事件,让我们在开发时不需要关注网络IO事件对应的细节,以及定时事件中应使用的数据结构,以及何时调用定时任务,所以只需要关注简单的注 ...

  8. 国产网络库libhv开源四周年回顾

    libhv是一个跨平台的c/c++网络库,本文写在libhv开源四周年之际,借机回顾了libhv的发展历程. github地址:https://github.com/ithewei/libhv 文章目 ...

  9. libevent多线程使用bufferevent的那些事

    void do_accept(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen ...

最新文章

  1. 【直播】王茂霖:二手车交易价格预测 Baseline 提高(河北高校数据挖掘邀请赛)
  2. 华为全球最快AI训练集群Atlas 900诞生
  3. 聊聊rocketmq的ProducerImpl
  4. 为VSFTP用户指定登录后的目录.原创测试通过.
  5. runtime运行时编程一些相关知识
  6. Win10远程桌面失败,这可能是由于CredSSP加密Oracle修正 解决方法
  7. python知识点博客园_python零碎知识点一
  8. Vue+Openlayers+el-radio实现切换地图显示
  9. flink check-point save-point理解
  10. LeetCode 1743. 从相邻元素对还原数组(拓扑排序)
  11. Adobe发布基于HTML5技术的网络开发工具以解决跨平台问题
  12. 天津市规划局存储和灾备系统集成项目
  13. 2021-09-02编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) 。
  14. x-bov16 firmware android,MSD0431XX 松下
  15. 汽车轮毂识别定位检测
  16. php踩过的那些坑(2) strpos引发的血案
  17. 中央处理器cpu中的什么是计算机的指挥中,计算机中央处理器CPU的组成有哪些
  18. Python+OpenCV判断图像是黑底还是白底
  19. java excel 模板 替换_java替换Excel字符
  20. 角点检测 c语言 棋盘格,一种棋盘格角点全自动检测方法与流程

热门文章

  1. 广义估计方程估计方法_广义估计方程简介
  2. 计算各位数字的平方和:
  3. Python3.6下CMD命令安装ipython
  4. css 的垂直居中和 图片居中
  5. Deepin Linux15 华为荣耀笔记本MagicBook2019使用-安装深度应用商店和应用软件
  6. jquery遍历得到的 Map 数据,
  7. c语言垃圾分类管理系统,RFID超高频垃圾分类车管理读写器
  8. 【JavaP6大纲】功能设计篇:秒杀场景设计
  9. 5.2 BGP水平分割
  10. 中科创达出席2021福布斯中国创新峰会