当前位置:   article > 正文

Libevent 官方文档学习笔记(2. bufferevent部分)_bufferevent官网

bufferevent官网

本文地址:https://segmentfault.com/a/1190000005601925


Libevent的辅助函数和数据类型

头文件<event2/util.h>。以下只列出我自己会用到的部分。

基本类型

evutil_socket_t
Socket的抽象。除了Windows之外,其他系统都是一个int类型。如果考虑Windows的兼容性的话,建议用这个类型。

标准整型

以下是几种数据长度的定义

  1. ----------------------------------------------------------
  2. Type 位宽 符号数 最大值 最小值
  3. ----------------------------------------------------------
  4. ev_uint64_t 64 x EV_UINT64_MAX 0
  5. ev_int64_t 64 √ EV_INT64_MAX EV_INT64_MIN
  6. ev_uint32_t 32 x EV_UINT32_MAX 0
  7. ev_int32_t 32 √ EV_INT32_MAX EV_INT32_MIN
  8. ev_uint16_t 16 x EV_UINT16_MAX 0
  9. ev_int16_t 16 √ EV_INT16_MAX EV_INT16_MIN
  10. ev_uint8_t 8 x EV_UINT8_MAX 0
  11. ev_int8_t 8 √ EV_INT8_MAX EV_INT8_MIN

其他一些类型
ev_ssize_t
ev_off_t

适配函数的宏

  1. #define evutili_timer_add(tvp, uvp, vvp)
  2. #define evutili_timer_sub(tvp, uvp, vvp)

计算timeval数据加减的宏,vvp = tvp +/- uvp。注意三者都要使用指针

  1. #define evutil_timerclear(tvp)
  2. #define evutil_timerisset(tvp)

将timeval清零,或者判断是否被清零

#define evutil_timercmp(tvp, uvp, cmp)
判断timeval的先后,其中cmp是比较富豪,比如==<=>=<>!=

int evutil_gettimeofday (struct timeval *tv, struct timezone *tz);

Socket相关的函数
  1. #define evutil_socket_geterror (sock)
  2. #define evutil_socket_error_to_string (errcode)

获得指定socket的error code,以及转为可读的string

int evutil_make_socket_nonblocking (evutil_sopcket_t sock);

将一个socket非阻塞。

字符串操作
  1. ev_int64_t evutil_strtoll (const char *s, char **endptr, int base);
  2. int evutil_snprintf (char *but, size_t buflen, const char *format, ...);
  3. int evutil_vsnprintf (char *bug, size_t buflen, const char *format, va_list ap);
数据结构体
#define evutil_offsetof (type, field)

Bufferevent:概念和基本知识

传统的libevent使用方法:

  1. 当需要放数据的时候,存入数据到buffer

  2. 等待socket可写

  3. 尽量向socket中写更多的data

  4. 如果还有data未写入,则再等待socket可写

使用头文件<event2/bufferevent.h>可以使用bufferevent,节省read/write调用,只需要将数据放入/取出一个buffer即可
  目前bufferevent只支持TCP,未来可能支持UDP
  每个bufferevent有一个read buffer和一个write buffer,都是struct evbuffer。这个后文再讲。

回调和bufferevent

Bufferevent使用叫做watermarks(水位线)的东西来定义回调函数的调用时机。有以下几个watermarks:
  Read low-water mark:当read buffer的量大于等于这么多时,调用callback。默认是0,即一有数据就回调。
  Read high-water mark:当read buffer的量大于等于这么多时,停止read,直到buffer里面的数据低于这个值为止,重新开始read。默认是无限。
  Write low-water mark:当write buffer的量小于等于这么多时,调用回调。默认是0
  Write high-water mark:bufferevent未直接使用这个值。参见后文

Bufferevent也有错误回调事件回调,用于告知一些非数据时间和错误。如下:
  BEV_EVENT_READING
  BEV_EVENT_WRITING
  BEV_EVENT_ERROR:操作发生错误。需要调用EVUTIL_SOCKET_ERROR()来判断出现了什么错误
  BEV_EVENT_TIMEOUT
  BEV_EVENT_EOF
  BEV_EVENT_CONNECTED:请求连接已经完成

延迟回调
一般情况下,bufferevent的callback时立刻调用的。但是如果调用关系很复杂的话可能会出bug,这个时候可以将bufferevent设置为延迟的(defered),这样会使得回调函数放在event loop中被执行,单线程。

Bufferevent的选项

BEV_OPT_CLOSE_ON_FREE:当bufferevent释放时,关闭底层传输
BEV_OPT_THREADSAFE:为bufferevent使用lock
BEV_OPT_DEFER_CALLBACKS:将callback设为延迟的
BEV_OPT_UNLOCK_CALLBACKS:默认情况下如果有THREADSAFE标志,调用callback时会加锁。使用这个标志是的即便有THREADSAFE标志,调用callback也不加锁

使用基于socket的bufferevent
  1. struct bufferevent *bufferevent_socket_new (
  2. struct event_base *base,
  3. evutil_socket_t fd,
  4. enum bufferevent_options options);

这里的fd可以不指定,此时fd的参数是-1。如果指定了fd,这个fd必须是已经nonblock的。

  1. int bufferevent_socket_connect (struct bufferevent *bev,
  2. struct sockaddr *address,
  3. int addrlen);

这是对connect()的封装。如果bev的fd是-1,那么会自动调用socket(),并且设置nonblock。,随后再异步调用connect();如果fd已经指定了,那么只是告诉bev去做connect()操作。
  正常情况下,这会引起BEV_EVENT_CONNECTED回调

  1. int bufferevent_socket_connect_hostname (
  2. struct bufferevent *bev,
  3. struct event_base *dns_base,
  4. int family,
  5. const char *hostname,
  6. int port);

这是connect()封装的另一个版本,但是目标改为hostname。这会导致bufferevent自动去解析DNS。其中family可选以下值:AF_INETAF_INET6AF_UNSPEC
  dns_base参数可选。如果是NULL,那么bufferevent会一直阻塞直到DNS解析完成——当然不推荐这么做。如果带了参数,则libevent会异步处理DNS请求。
  剩下的工作与上面的connect封装相同。

int bufferevent_socket_get_dns_error (struct bufferevent *bev);
通用的bufferevent操作
void bufferevent_free (struct bufferevent *bev);

释放bfferevent。如果callback是defered的,那么bufferevent会等到callback返回之后才释放。如果指定了BEV_OPT_CLOSE_ON_FREE,那么socket也会被close掉。

  1. typedef void (*bufferevent_data_cb) (struct bufferevent *bev, void *ctx);
  2. typedef void (*bufferevent_event_cb) (struct bufferevent *bev, short events, void *ctx);
  3. void buffevent_setcb (struct buffevent *bufev,
  4. bufferevent_data_cb readcb,
  5. bufferevent_data_cb writecb,
  6. bufferevent_event_cb eventcb,
  7. void *cbarg);
  8. void bufferevent_get_cb (struct buffevent *bufev,
  9. bufferevent_data_cb *readcb_ptr,
  10. bufferevent_data_cb *writecb_ptr,
  11. bufferevent_event_cb *eventcb_ptr,
  12. void **cbarg_ptr);

设置。获取bufferevent的callback。如果不想使用某个callback,则传入NULL。

  1. void bufferevent_enable (struct bufferevent *bufev, short events);
  2. void bufferevent_disable (struct bufferevent *bufev, short events);
  3. short bufferevent_getenabled (struct bufferevent *bufev);

使能/禁用指定的的callback。默认情况下,刚初始化的bufferevent,write使能,而read禁止。

  1. void bufferevent_setwatermark (struct buffevent *bev,
  2. short events,
  3. size_t lowmark,
  4. size_t highmark);

设置watermark。对于high-watermark,0表示无限。

  1. struct evbuffer *bufferevent_get_input (struct bufferevent *bev);
  2. struct evbuffer *bufferevent_get_output(struct bufferevent *bev);

获取到bufferevent中对应的read/write buffer。

  1. int bufferevent_write (struct bufferevent *ev, const void *data, size_t size);
  2. int bufferevent_write_buffer (struct bufferevent *bev, struct evbuffer *buf);

函数一:直接向bufferevent附加数据函数二:将evbuffer的全部内容附加到bufferevent中并晴空evbuffer

  1. size_t bufferevent_read (struct bufferevent *bev, void *data, size_t size);
  2. int bufferevent_read_buffer (struct bufferevent *bev, struct evbuffer *buf);

函数一:直接从bufferevent中读出数据,返回数据长度函数二:将bufferevent中的全部数据抽取到evbuffer中

  1. void bufferevent_set_timeouts (struct bufferevent *bev,
  2. const struct timeval *timeout_read,
  3. const struct timeval *timeout_write);

设置timeout,使得当一段时间没有数据时,触发回调函数。此时的实践中会包含 BEV_EVENT_TIMEOUT

  1. int bufferevent_flush (struct bufferevent *bufev,
  2. short iotype,
  3. enum bufferevent_flush_mode state);

强制读/写尽可能多的数据。这个函数目前对socket没有作用。

类型特定的bufferevent函数

以下几个函数的含义正如字面意思,就不特别说明了

  1. int bufferevent_priority_set (struct bufferevent *bev, int pri);
  2. int bufferevent_get_priority (struct bufferevent *bev);
  3. int bufferevent_setfd (struct bufferevent *bev, evutil_socket_t fd);
  4. evutil_socket_t bufferevent_getfd (struct bufferevent *bev);
  5. struct event_base *bufferevent_get_base (struct bufferevent *bev);
  6. struct bufferevent *bufferevent_get_underlying (struct bufferevent *bev);
  7. void bufferevent_lock (struct bufferevent *bev);
  8. void buyfferevent_unlock(struct bufferevent *bev);

Bufferevents:高级主题

这里讲了很多bufferevent的高级功能。本文章只是列出其中会使用到的部分

限制每次read/write的长度
  1. int bufferevent_set_max_single_read (struct bufferevent *bev, size_t size);
  2. int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size);

同时也有相对应的get函数

速率(带宽)限制
  1. #define EV_RATE_LIMIT_MAX EV_SSIZE_MAX
  2. struct ev_token_bucket_cfg;
  3. struct ev_token_bucket_cfg *ev_token_bucket_cfg_new (
  4. size_t read_rate, size_t read_burst,
  5. size_t write_rate, size_t write_burst,
  6. const struct timeval *tick_len);
  7. void ev_token_bucket_cfg_free (struct ev_token_bucket_cfg *cfg);
  8. int bufferevent_set_rate_limit (struct bufferevent *bev,
  9. struct ev_token_bucket_cfg *cfg);

其中ev_token_bucket_cfg_new()的前四个函数的单位均为bytes/tick,而tick的单位由tick_len指定。如果tick_len为NULL,那么默认为1秒。

Bufferevents 和 SSL

这里其实是一个很重要的内容,讲的是如何在bufferevent中使用SSL。Libevent将SSL深度耦合了进来,使得你可以很方便地使用bufferevent来完成SSL通信。
  呃,缺点就是libevent和OpenSSL的缺点的集合。其实对于嵌入式开发来说,因为CPU是分立的,所以性能上的缺点并不明显,最大的问题是占用磁盘空间啊!Libevent的库本身就不小,加上OpenSSL更是超大。我弄懂libevent的时候,我们的系统已经准备改用其他的异步I/O和SSL库,所以我也就不看了
  另外吐槽一下:我们这么多年了还是没时间把libevent和OpenSSL完全替换的工作做完,在这期间我自己都把libev、libuv、PolarSSL(mbedTLS)、cyaSSL看了……

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/742732
推荐阅读
相关标签
  

闽ICP备14008679号