Libevent安装与使用(二)

Bufferevents
Every bufferevent has an input buffer and an output buffer. These are of type "struct evbuffer". When you have data to write on
a bufferevent, you add it to the output buffer; when a bufferevent has data for you to read, you drain it from the input buffer.

 

示例源码

 

每个bufferevent有两个数据相关的回调:一个读取回调和一个写入回调。默认情况下,从底层传输端口读取了任意量的数据之后会调用读取回调;输出缓冲区中足够量的数据被清空到底层传输端口后写入回调会被调用。通过调整 bufferevent 的读取和写入“水位(watermarks) ”可以覆盖这些函数的默认行为。

每个bufferevent有四个水位:
读取低水位: 读取操作使得输入缓冲区的数据量在此级别或者更高时, 读取回调将被调用。 默认值为0, 所以每个读取操作都会导致读取回调被调用。
读取高水位:输入缓冲区中的数据量达到此级别后, bufferevent将停止读取, 直到输入缓冲区中足够量的数据被抽取, 使得数据量低于此级别。 默认值是无限, 所以永远不会因为输入缓冲区的大小而停止读取。
写入低水位: 写入操作使得输出缓冲区的数据量达到或者低于此级别时, 写入回调将被调用。默认值是0,所以只有输出缓冲区空的时候才会调用写入回调。
写入高水位: bufferevent 没有直接使用这个水位。它在 bufferevent 用作另外一个bufferevent的底层传输端口时有特殊意义。 请看后面关于过滤型bufferevent的介绍。

bufferevent也有“错误”或者“事件”回调, 用于向应用通知非面向数据的事件, 如连接已经关闭或者发生错误。定义了下列事件标志:
BEV_EVENT_READING:读取操作时发生某事件,具体是哪种事件请看其他标志。
BEV_EVENT_WRITING:写入操作时发生某事件,具体是哪种事件请看其他标志。
BEV_EVENT_ERROR:操作时发生错误。关于错误的更多信息,请调 用EVUTIL_SOCKET_ERROR()。
BEV_EVENT_TIMEOUT:发生超时。
BEV_EVENT_EOF:遇到文件结束指示。
BEV_EVENT_CONNECTED:请求的连接过程已经完成

bufferevent的选项标志
创建bufferevent 时可以使用一个或者多个标志修改其行为。可识别的标志有:
BEV_OPT_CLOSE_ON_FREE:释放 bufferevent 时关闭底层传输端口。这将关闭底层套接字,释放底层bufferevent 等。
BEV_OPT_THREADSAFE:自动为 bufferevent 分配锁,这样就可以安全地在多个线程中使用bufferevent。
BEV_OPT_DEFER_CALLBACKS:设置这个标志时, bufferevent 延迟所有回调,如上所述。
BEV_OPT_UNLOCK_CALLBACKS:默认情况下,如果设置 bufferevent 为线程安全的,则bufferevent 会在调用用户提供的回调时进行锁定。设置这个选项会让libevent在执行回调的时候不进行锁定。

与基于套接字的bufferevent一起工作
基于套接字的bufferevent是最简单的,它使用libevent的底层事件机制来检测底层网络套接字是否已经就绪,可以进行读写操作,并且使用底层网络调用(如 readv、 writev、WSASend、 WSARecv)来发送和接收数据。

 

示例源码:https://github.com/wanfeng42/chat

 

接口

struct bufferevent *bufferevent_socket_new(struct event_base *base,
                          evutil_socket_t fd,
enum bufferevent_options options);


The base is an event_base, and options is a bitmask of bufferevent options (BEV_OPT_CLOSE_ON_FREE, etc). The fd argument is an optional file descriptor for a socket. You can set fd to -1 if you want to set the file descriptor later.

/**************************************/

int bufferevent_socket_connect(struct bufferevent *bev,
                  struct sockaddr *address, 
                  int addrlen);

The address and addrlen arguments are as for the standard call connect(). If the bufferevent does not already have a socket set,
calling this function allocates a new stream socket for it, and makes it nonblocking.
If the bufferevent does have a socket already, calling bufferevent_socket_connect() tells Libevent that the socket is not connected,
and no reads or writes should be done on the socket until the connect operation has succeeded.
It is okay to add data to the output buffer before the connect is done.
This function returns 0 if the connect was successfully launched, and -1 if an error occurred.

Note that you only get a BEV_EVENT_CONNECTED event if you launch the connect() attempt using bufferevent_socket_connect().
If you call connect() on your own, the connection gets reported as a write.

/**************************************/

void bufferevent_free(struct bufferevent *bev);

This function frees a bufferevent. Bufferevents are internally reference-counted, so if the bufferevent has pending deferred
callbacks when you free it, it won’t be deleted until the callbacks are done.
The bufferevent_free() function does, however, try to free the bufferevent as soon as possible. If there is pending data to write on
the bufferevent, it probably won’t be flushed before the bufferevent is freed.
If the BEV_OPT_CLOSE_ON_FREE flag was set, and this bufferevent has a socket or underlying bufferevent associated with it
as its transport, that transport is closed when you free the bufferevent.

/**************************************/

int bufferevent_flush(struct bufferevent *bufev,
                  short iotype, 
             enum bufferevent_flush_mode state);


Flushing a bufferevent tells the bufferevent to force as many bytes as possible to be read to or written from the underlying
transport, ignoring other restrictions that might otherwise keep them from being written. Its detailed function depends on the
type of the bufferevent.
The iotype argument should be EV_READ, EV_WRITE, or EV_READ|EV_WRITE to indicate whether bytes being read, written, or both should be processed. The state argument may be one of BEV_NORMAL, BEV_FLUSH, or BEV_FINISHED.
BEV_FINISHED indicates that the other side should be told that no more data will be sent; the distinction between BEV_NORMAL
and BEV_FLUSH depends on the type of the bufferevent.
The bufferevent_flush() function returns -1 on failure, 0 if no data was flushed, or 1 if some data was flushed.

/**************************************/

typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);

typedef void (*bufferevent_event_cb)(struct bufferevent *bev,
                      short events, void *ctx);

void bufferevent_setcb(struct bufferevent *bufev,
              bufferevent_data_cb readcb, 
              bufferevent_data_cb writecb,               bufferevent_event_cb eventcb,
              void *cbarg); void bufferevent_getcb(struct bufferevent *bufev,               bufferevent_data_cb *readcb_ptr,               bufferevent_data_cb *writecb_ptr,               bufferevent_event_cb *eventcb_ptr,               void **cbarg_ptr);

 

The bufferevent_setcb() function changes one or more of the callbacks of a bufferevent. The readcb, writecb, and eventcb
functions are called (respectively) when enough data is read, when enough data is written, or when an event occurs.The first
argument of each is the bufferevent that has had the event happen. The last argument is the value provided by the user in the cbarg
parameter of bufferevent_callcb(): You can use this to pass data to your callbacks. The events argument of the event callback is
a bitmask of event flags: see "callbacks and watermarks" above.
You can disable a callback by passing NULL instead of the callback function. Note all the callback functions on a bufferevent
share a single cbarg value, so changing it will affect all of them.

/**************************************/

void bufferevent_enable(struct bufferevent *bufev, short events);
void bufferevent_disable(struct bufferevent *bufev, short events);

You can enable or disable the events EV_READ, EV_WRITE, or EV_READ|EV_WRITE on a bufferevent. When reading or
writing is not enabled, the bufferevent will not try to read or write data.
By default, a newly created bufferevent has writing enabled, but not reading.

/**************************************/

void bufferevent_setwatermark(struct bufferevent *bufev, 
                  short events,                   size_t lowmark,
                  size_t highmark);

 

The bufferevent_setwatermark() function adjusts the read watermarks, the write watermarks, or both, of a single bufferevent.
(If EV_READ is set in the events field, the read watermarks are adjusted. If EV_WRITE is set in the events field, the write
watermarks are adjusted.)
A high-water mark of 0 is equivalent to "unlimited".

/**************************************/

struct evbuffer *bufferevent_get_input(struct bufferevent *bufev);
struct evbuffer *bufferevent_get_output(struct bufferevent *bufev);

 

These two functions are very powerful fundamental: they return the input and output buffers respectively.
If writing on the bufferevent was stalled because of too little data (or if reading was stalled because of too much), then adding
data to the output buffer (or removing data from the input buffer) will automatically restart it.

/**************************************/

int bufferevent_write(struct bufferevent *bufev,
              const void *data, 
              size_t size);
int bufferevent_write_buffer(struct bufferevent *bufev,                   struct evbuffer *buf);

 

These functions add data to a bufferevent’s output buffer. Calling bufferevent_write() adds size bytes from the memory at data
to the end of the output buffer. Calling bufferevent_write_buffer() removes the entire contents of buf and puts them at the end of
the output buffer. Both return 0 if successful, or -1 if an error occurred.

/**************************************/

size_t bufferevent_read(struct bufferevent *bufev,
               void *data,
               size_t size);
int bufferevent_read_buffer(struct bufferevent *bufev,
                 struct evbuffer *buf);

 

These functions remove data from a bufferevent’s input buffer. The bufferevent_read() function removes up to size bytes
from the input buffer, storing them into the memory at data. It returns the number of bytes actually removed. The bufferevent_read_buffer() function drains the entire contents of the input buffer and places them into buf ; it returns 0 on success and-1 on failure.

/**************************************/

enum evbuffer_eol_style {
EVBUFFER_EOL_ANY,
EVBUFFER_EOL_CRLF,
EVBUFFER_EOL_CRLF_STRICT,
EVBUFFER_EOL_LF,
EVBUFFER_EOL_NUL
};

char *evbuffer_readln(struct evbuffer *buffer,
               size_t *n_read_out,                enum evbuffer_eol_style eol_style);

 

Many Internet protocols use line-based formats. The evbuffer_readln() function extracts a line from the front of an evbuffer and
returns it in a newly allocated NUL-terminated string. If n_read_out is not NULL, *n_read_out is set to the number of bytes
in the string returned. If there is not a whole line to read, the function returns NULL. The line terminator is not included in the
copied string.
The evbuffer_readln() function understands 4 line termination formats:
EVBUFFER_EOL_LF
The end of a line is a single linefeed character. (This is also known as "\n". It is ASCII value is 0x0A.)
EVBUFFER_EOL_CRLF_STRICT
The end of a line is a single carriage return, followed by a single linefeed. (This is also known as "\r\n". The ASCII values
are 0x0D 0x0A).
EVBUFFER_EOL_CRLF
The end of the line is an optional carriage return, followed by a linefeed. (In other words, it is either a "\r\n" or a "\n".) This
format is useful in parsing text-based Internet protocols, since the standards generally prescribe a "\r\n" line-terminator,
but nonconformant clients sometimes say just "\n".
EVBUFFER_EOL_ANY
The end of line is any sequence of any number of carriage return and linefeed characters. This format is not very useful; it
exists mainly for backward compatibility.
EVBUFFER_EOL_NUL
The end of line is a single byte with the value 0 — that is, an ASCII NUL.
(Note that if you used event_set_mem_functions() to override the default malloc, the string returned by evbuffer_readln will be
allocated by the malloc-replacement you specified.)

/**************************************/

 

int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen);

This function appends the datlen bytes in data to the end of buf. It returns 0 on success, and -1 on failure.

int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap);

These functions append formatted data to the end of buf. The format argument and other remaining arguments are handled as if
by the C library functions "printf" and "vprintf" respectively. The functions return the number of bytes appended.

/**************************************/

int evbuffer_drain(struct evbuffer *buf, size_t len);
int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen);

The evbuffer_remove() function copies and removes the first datlen bytes from the front of buf into the memory at data. If there
are fewer than datlen bytes available, the function copies all the bytes there are. The return value is -1 on failure, and is otherwise
the number of bytes copied.
The evbuffer_drain() function behaves as evbuffer_remove(), except that it does not copy the data: it just removes it from the
front of the buffer. It returns 0 on success and -1 on failure.

/**************************************/

posted @ 2018-08-07 20:13  wanfeng_42  阅读(195)  评论(0编辑  收藏  举报