1

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

 Evbuffers: 缓冲化的I/O实用工具 


头文件:<event2/buffer.h>

Evbuffer基本操作

struct evbuffer *evbuffer_new (void);
void evbuffer_free (struct evbuffer *buf);

创建/销毁evbuffer

int evbuffer_enable_locking (struct evbuffer *buf, void *lock);
void evbuffer_lock (struct evbuffer *buf);
void evbuffer_unlock (struct evbuffer *buf);

第一个函数,参数locking传入的参数是一个锁。可以传入NULL,让evbffer自动创建一个锁。

size_t evbuffer_get_length (const struct evbuffer *buf);
size_t evbuffer_get_continous_space (const struct evbuffer *buf);

第一个函数,获取当前evbuffer的总数据长度。第二个函数,由于数据在evbuffer的内存中并不是连续保存的,这里返回第一个chunk的大小。

操作evbuffer中的帧

int evbuffer_add (struct evbuffer *buf, const void *data, size_t data_len);
int evbuffer_add_printf (struct evbuffer *buf, const char *fmt);
int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap);

直接往evbuffer的末尾添加数据


int evbuffer_expand (struct evbuffer *buf, size_t data_len);

扩展ev_buffer的预申请内存


int evbuffer_add_buffer (struct evbuffer *dst, struct evbuffer *src);
int evbuffer_rename_buffer (struct evubffer *src, struct evbuffer *dst, size_t data_len);

两个函数都是“move”操作,也就是说会删除src的指定内容。


int evbuffer_prepend (struct evbuffer *buf, const void *data, size_t size);
int evbuffer_prepend_buffer (struct evbuffer *dst, struct evbuffer *src);

这两个函数是往evbuffer的头部插入数据


unsigned char *evbuffer_pullup (struct evbuffer *buf, ev_ssize_t size);

将指定长度的数据存入到evbuffer的第一个chunk中。如果size为-1,则表示全部。


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

从evbuffer的头部放走指定长度的数据,第二个函数可以顺带读出来。

基于字符串行的输入

很多文件都是一行一行存储的(比如文本),一下函数可以用来一行一行地读取输入(ASCII)。读取之前要指定行尾的格式。

enum evbuffer_eol_style {
    EVBUFFER_EOL_ANY,            // 任意数量的\r和\n
    EVBUFFER_EOL_CRLF,           // \r或者\r\n
    EVBUFFER_EOL_CRLF_STRICT,    // \r\n
    EVBUFFER_EOL_LF,             // \n
    EVBUFFER_EOL_NUL             // \0
};
char *evbuffer_readln (struct evbuffer *buffer,
                       size_t *n_read_out,
                       enum evbuffer_eol_style eol_style);

在evbuffer里面搜索

Evbuffer使用一个结构体来配置搜索功能,其中pos表示position,如下:

struct evbuffer_ptr {
    ev_ssize_t pos;
    struct {/* internal fields */} _internal;
};
struct evbuffer_ptr evbuffer_search (struct evbuffer *buffer,
                                     const char *what,
                                     size_t len,
                                     const struct evbuffer_ptr *start);
struct evbuffer_ptr evbuffer_search_range (struct evbuffer *buffer,
                                           const char *what,
                                           size_t len,
                                           const struct evbuffer_ptr *start,
                                           const struct evbuffer_ptr *end);
struct evbuffer_ptr evbuffer_search_eol (struct evbuffer_ptr *buffer,
                                         struct evbuffer_ptr *start,
                                         size_t *eol_len_out,
                                         enum evbuffer_eol_style eol_style);

第一个参数是搜索在evbuffer中与“what”参数相同的数据并且返回。如果参数start不为空,则会从start中所指定的位置开始搜索。
  第二个函数的不同是指定了一个搜索范围;第三个函数类似于evbuffer_readln,但是不复制,只是返回结果而已。


enum evbuffer_ptr_how {
    EVBUFFER_PTR_SET,
    EVBUFFER_PTR_ADD,
};
int evbuffer_ptr_set (struct evbuffer *buffer,
                      struct evbuffer_ptr *pos,
                      size_t position,
                      enum evbuffer_ptr_how how);

修改evbuffer中的evbuffer_ptr。

检查数据但是不复制出来

sruct aevbuffer_iovec {
    void *iov_base;
    size_t iov_len;
};
int evbuffer_peak (struct evbuffer *buffer,
                   ev_size_t len,
                   struct evbuffer_ptr *start_atm
                   struct evbuffer_iovec *vec_out,
                   int n_vec);

这个函数给予一个struct evbuffer_iovec数组,并且用n_vec制定长度,从evbuffer中得到的具体数据块的信息,这样就可以直接读取了。
如果start_at非空,则直接从制定的位置读起。

直接向evbuffer添加数据

int evbuffer_reserve_space (struct evbuffer *buf,
                            ev_size_t size,
                            struct evbuffer_iovec *vec,
                            int n_vecs);
int evbuffer_commit_space (struct evbuffer *buf,
                           struct evbuffer_iovec *vec,
                           int n_vecs);

这个函数与peak类似,不同的是使用这个组合,可以直接修改evbuffer里面的值。
如果是多线程的情况下,注意要在reserve之前加锁、commit之后解锁。

使用evbuffer对网络I/O进行读写

int evbuffer_write (struct evbuffer *buffer, evutil_socket_t fd);
int evbuffer_write_almost (struct evbuffer *buffer, evutil_socket_t fd, ev_ssize_t howmuch);
int evubffer_read (struct evbuffer *buffer, evutil_socket_t fd, ev_ssize_t howmuch);

evbuffer_write等同于evbuffer_write_almost中的howmuch参数指定为-1。

Evbuffer的回调函数

struct evbuffer_cb_info {
    size_t orig_size;
    size_t n_added;
    size_t n_deleted;
};
typedef void (*evbuffer_cb_func)(struct evbuffer *buffer,
                                 const struct evbuffer_cb_info *info,
                                 void *arg);
                                 
struct evbuffer_cb_func;
struct evbuffer_cb_func *evbuffer_add_cb (struct evbuffer *buffer,
                                           evbuffer_cb_func cb,
                                           void *cbarg);

evbuffer有操作时,会调用callback,返回entry,则可以用来在后续的函数中引用这个callback。

int evbuffer_remove_cb_entry (struct evbuffer *buffer, struct evbuffer_cb_func *ent);
int evbuffer_remove_cb (struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg);

这两个函数用于删除callback

int evbuffer_defer_callbacks (struct evbuffer *buffer, struct event_base *base);

Evbuffer的callback也可以放在event loop里面,这两个函数就是将callback进行defer的函数

为基于evbuffer的I/O减少数据复制

基于evbuffer经常会有数据复制,但是很多大负荷的服务器要尽量减少这些操作,此时就需要以下函数:

typedef void (*evbuffer_ref_cleanup_cb) (const void *data, size_t datalen, void *extra);
int evbuffer_add_reference (struct evbuffer *outbuf, 
                            const void *data, 
                            size_t datalen, 
                            evbufferref_cleanup_cb cleanupfn, 
                            void *extra);

这个函数通过引用想evbuffer添加一段void *数据并且指定其长度。这段数据必须持续保持有效,直到evbuffer调用callback为止。

向evbuffer直接添加文件内容

(很少用,暂略)

evbuffer之间的复制

int evbuffer_add_buffer_reference (struct evbuffer *outbuf, struct evbuffer *inbuf);

暂时冻结evbuffer

int evbuffer_freeze (struct evbuffer *buf, int at_front);
int evbuffer_unfreeze (struct evbuffer *buf, int at_front);

系列篇

Libevent官方文档学习笔记(1. libevent_core部分)
Libevent官方文档学习笔记(2. bufferevent部分)
Libevent官方文档学习笔记(3. evbuffer部分)(本文)


amc
927 声望228 粉丝

电子和互联网深耕多年,拥有丰富的嵌入式和服务器开发经验。现负责腾讯心悦俱乐部后台开发