本文地址:http://www.javashuo.com/article/p-unzqmpqa-mk.htmlsegmentfault
头文件是<event2/util.h>
。如下只列出我本身会用到的部分。数据结构
evutil_socket_t
Socket的抽象。除了Windows以外,其余系统都是一个int类型。若是考虑Windows的兼容性的话,建议用这个类型。异步
标准整型socket
如下是几种数据长度的定义函数
---------------------------------------------------------- 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
oop
适配函数的宏性能
#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清零,或者判断是否被清零ui
#define evutil_timercmp(tvp, uvp, cmp)
判断timeval的前后,其中cmp是比较富豪,好比==
, <=
, >=
, <
, >
, !=
线程
int evutil_gettimeofday (struct timeval *tv, struct timezone *tz);
#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)
传统的libevent使用方法:
使用头文件<event2/bufferevent.h>
可使用bufferevent,节省read/write调用,只须要将数据放入/取出一个buffer便可
目前bufferevent只支持TCP,将来可能支持UDP
每一个bufferevent有一个read buffer和一个write buffer,都是struct evbuffer
。这个后文再讲。
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中被执行,单线程。
BEV_OPT_CLOSE_ON_FREE
:当bufferevent释放时,关闭底层传输BEV_OPT_THREADSAFE
:为bufferevent使用lockBEV_OPT_DEFER_CALLBACKS
:将callback设为延迟的BEV_OPT_UNLOCK_CALLBACKS
:默认状况下若是有THREADSAFE标志,调用callback时会加锁。使用这个标志是的即使有THREADSAFE标志,调用callback也不加锁
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);
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没有做用。
如下几个函数的含义正如字面意思,就不特别说明了
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);
这里讲了不少bufferevent的高级功能。本文章只是列出其中会使用到的部分
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_MAX struct 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秒。
这里实际上是一个很重要的内容,讲的是如何在bufferevent中使用SSL。Libevent将SSL深度耦合了进来,使得你能够很方便地使用bufferevent来完成SSL通讯。
呃,缺点就是libevent和OpenSSL的缺点的集合。其实对于嵌入式开发来讲,由于CPU是分立的,因此性能上的缺点并不明显,最大的问题是占用磁盘空间啊!Libevent的库自己就不小,加上OpenSSL更是超大。我弄懂libevent的时候,咱们的系统已经准备改用其余的异步I/O和SSL库,因此我也就不看了
另外吐槽一下:咱们这么多年了仍是没时间把libevent和OpenSSL彻底替换的工做作完,在这期间我本身都把libev、libuv、PolarSSL(mbedTLS)、cyaSSL看了……
Libevent官方文档学习笔记(1. libevent_core部分)
Libevent官方文档学习笔记(2. bufferevent部分)(本文)
Libevent官方文档学习笔记(3. evbuffer部分)