Libevent官方文档学习笔记(bufferevent部分)
Libevent的辅助函数和数据类型
头文件是。以下只列出我自己会用到的部分。
基本类型
evutil_socket_t
Socket的抽象。除了Windows之外,其他系统都是一个int类型。如果考虑Windows的兼容性的话,建议用这个类型。
标准整型
以下是几种数据长度的定义
---------------------------------------------------------- Type 位宽 符号数 最大值 最小值 ---------------------------------------------------------- ev_uint64_t 64 x EV_UINT64_MAX 0 ev_int64_t 64 √ EV_INT64_MAX EV_INT64_MIN ev_uint32_t 32 x EV_UINT32_MAX 0 ev_int32_t 32 √ EV_INT32_MAX EV_INT32_MIN ev_uint16_t 16 x EV_UINT16_MAX 0 ev_int16_t 16 √ EV_INT16_MAX EV_INT16_MIN ev_uint8_t 8 x EV_UINT8_MAX 0 ev_int8_t 8 √ EV_INT8_MAX EV_INT8_MIN
其他一些类型
ev_ssize_t
ev_off_t
适配函数的宏
# define evutili_timer_add(tvp, uvp, vvp)# define evutili_timer_sub(tvp, uvp, vvp)
计算timeval数据加减的宏,vvp = tvp +/- uvp。注意三者都要使用指针
# define evutil_timerclear(tvp)# define evutil_timerisset(tvp)
将timeval清零,或者判断是否被清零
define evutil_timercmp(tvp, uvp, cmp)
判断timeval的先后,其中cmp是比较富豪,比如==, , >=, , >, !=
int evutil_gettimeofday (struct timeval tv, struct timezone tz);
Socket相关的函数
# define evutil_socket_geterror (sock)# define evutil_socket_error_to_string (errcode)
获得指定socket的error code,以及转为可读的string
int evutil_make_socket_nonblocking (evutil_sopcket_t sock);
将一个socket非阻塞。
字符串操作
ev_int64_t evutil_strtoll (const char *s, char endptr, int base);int evutil_snprintf (char *but, size_t buflen, const char *format, ...);int evutil_vsnprintf (char *bug, size_t buflen, const char *format, va_list ap);
数据结构体
# define evutil_offsetof (type, field)
Bufferevent:概念和基本知识
传统的libevent使用方法:
当需要放数据的时候,存入数据到buffer
等待socket可写
尽量向socket中写更多的data
如果还有data未写入,则再等待socket可写
使用头文件可以使用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
struct bufferevent *bufferevent_socket_new ( struct event_base *base, evutil_socket_t fd, enum bufferevent_options options);
这里的fd可以不指定,此时fd的参数是-1。如果指定了fd,这个fd必须是已经nonblock的。
int bufferevent_socket_connect (struct bufferevent *bev, struct sockaddr *address, int addrlen);
这是对connect()的封装。如果bev的fd是-1,那么会自动调用socket(),并且设置nonblock。,随后再异步调用connect();如果fd已经指定了,那么只是告诉bev去做connect()操作。
正常情况下,这会引起BEV_EVENT_CONNECTED回调
int bufferevent_socket_connect_hostname ( struct bufferevent *bev, struct event_base *dns_base, int family, const char *hostname, int port);
这是connect()封装的另一个版本,但是目标改为hostname。这会导致bufferevent自动去解析DNS。其中family可选以下值:AF_INET, AF_INET6, AF_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掉。
typedef void (*bufferevent_data_cb) (struct bufferevent *bev, void *ctx);typedef void (*bufferevent_event_cb) (struct bufferevent *bev, short events, void *ctx);void buffevent_setcb (struct buffevent *bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg);void bufferevent_get_cb (struct buffevent *bufev, bufferevent_data_cb *readcb_ptr, bufferevent_data_cb *writecb_ptr, bufferevent_event_cb *eventcb_ptr, void cbarg_ptr);
设置。获取bufferevent的callback。如果不想使用某个callback,则传入NULL。
void bufferevent_enable (struct bufferevent *bufev, short events);void bufferevent_disable (struct bufferevent *bufev, short events);short bufferevent_getenabled (struct bufferevent *bufev);
使能/禁用指定的的callback。默认情况下,刚初始化的bufferevent,write使能,而read禁止。
void bufferevent_setwatermark (struct buffevent *bev, short events, size_t lowmark, size_t highmark);
设置watermark。对于high-watermark,0表示无限。
struct evbuffer *bufferevent_get_input (struct bufferevent *bev);struct evbuffer *bufferevent_get_output(struct bufferevent *bev);
获取到bufferevent中对应的read/write buffer。
int bufferevent_write (struct bufferevent *ev, const void *data, size_t size);int bufferevent_write_buffer (struct bufferevent *bev, struct evbuffer *buf);
函数一:直接向bufferevent附加数据
函数二:将evbuffer的全部内容附加到bufferevent中并晴空evbuffer
size_t bufferevent_read (struct bufferevent *bev, void *data, size_t size);int bufferevent_read_buffer (struct bufferevent *bev, struct evbuffer *buf);
函数一:直接从bufferevent中读出数据,返回数据长度
函数二:将bufferevent中的全部数据抽取到evbuffer中
void bufferevent_set_timeouts (struct bufferevent *bev, const struct timeval *timeout_read, const struct timeval *timeout_write);
设置timeout,使得当一段时间没有数据时,触发回调函数。此时的实践中会包含 BEV_EVENT_TIMEOUT位
int bufferevent_flush (struct bufferevent *bufev, short iotype, enum bufferevent_flush_mode state);
强制读/写尽可能多的数据。这个函数目前对socket没有作用。
类型特定的bufferevent函数
以下几个函数的含义正如字面意思,就不特别说明了
int bufferevent_priority_set (struct bufferevent *bev, int pri);int bufferevent_get_priority (struct bufferevent *bev);int bufferevent_setfd (struct bufferevent *bev, evutil_socket_t fd);evutil_socket_t bufferevent_getfd (struct bufferevent *bev);struct event_base *bufferevent_get_base (struct bufferevent *bev);struct bufferevent *bufferevent_get_underlying (struct bufferevent *bev);void bufferevent_lock (struct bufferevent *bev);void buyfferevent_unlock(struct bufferevent *bev);
Bufferevents:高级主题
这里讲了很多bufferevent的高级功能。本文章只是列出其中会使用到的部分
限制每次read/write的长度
int bufferevent_set_max_single_read (struct bufferevent *bev, size_t size);int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size);
同时也有相对应的get函数
速率(带宽)限制
# define EV_RATE_LIMIT_MAX EV_SSIZE_MAXstruct ev_token_bucket_cfg;struct ev_token_bucket_cfg *ev_token_bucket_cfg_new ( size_t read_rate, size_t read_burst, size_t write_rate, size_t write_burst, const struct timeval *tick_len);void ev_token_bucket_cfg_free (struct ev_token_bucket_cfg *cfg);int bufferevent_set_rate_limit (struct bufferevent *bev, 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看了……
关键字:c, libevent, 异步, 异步io
版权声明
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!