(5)libevent evbuffer
数据封装evBuffer
libevent 的 evbuffer 实现了为向后面添加数据和从前面移除数据而优化的字节队列。
1. 创建和释放evbuffer
struct evbuffer *evbuffer_new(void); // 分配和返回一个新的空 evbuffer
void evbuffer_free(struct evbuffer *buf); // 释放 evbuffer 和其内容。
2. 创建和释放evconnlistener
evconnlistener_new() 函数的 flags 参数传入一些标志
- LEV_OPT_LEAVE_SOCKETS_BLOCKING 接收新套接字后, 设置为非阻塞的
- LEV_OPT_CLOSE_ON_FREE 释放连接监听器会关闭底层套接字
- LEV_OPT_CLOSE_ON_EXEC 连接监听器会为底层套接字设置 close-on-exec 标志
- LEV_OPT_REUSEABLE 套接字是可重用的
- LEV_OPT_THREADSAFE 为监听器分配锁
/* 链接监听器回调 */
typedef void (*evconnlistener_cb)(struct evconnlistener *listener,
evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr);
/* 假定已经将套接字绑定到要监听的端口,然后通过 fd 传入这个套接字 */
struct evconnlistener *evconnlistener_new(struct event_base *base,
evconnlistener_cb cb, // 新连接到达时,监听 器调用你给出的回调函数。
void *ptr, // ptr 指针将传递给回调函数。
unsigned flags, // 参数控制回调函数的行为,下面会更详细论述。
int backlog, // 最大未决连接数。
evutil_socket_t fd);
/* 分配和绑定套接字, 传输要绑定到的地址和地址长度 */
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
evconnlistener_cb cb, // 新连接到达时,监听 器调用你给出的回调函数。
void *ptr, // ptr 指针将传递给回调函数。
unsigned flags, flags // 参数控制回调函数的行为,下面会更详细论述。
int backlog, // 最大未决连接数。
const struct sockaddr *sa,
int socklen);
void evconnlistener_free(struct evconnlistener *lev);
3.evbuffer与线程安全
- 默认情况下,在多个线程中同时访问 evbuffer 是不安全的。可以调用 evbuffer_enable_locking() 。如果 lock 参数为 NULL , libevent 会使用evthread_set_lock_creation_callback 提供的锁创建函数创建一个锁 。否则,libevent 将 lock 参数用作锁。
- evbuffer_lock()和 evbuffer_unlock()函数分别请求和释放 evbuffer 上的锁。可以使用这两个函数让一系列操作是原子的。如果 evbuffer 没有启用锁,这两个函数不做任何操作。
int evbuffer_enable_locking(struct evbuffer *buf, void *lock);
void evbuffer_lock(struct evbuffer *buf);
void evbuffer_unlock(struct evbuffer *buf);
4.启用和禁用 evconnlistener
int evconnlistener_disable(struct evconnlistener *lev);
int evconnlistener_enable(struct evconnlistener *lev);
5.调整 evconnlistener 的回调函数
void evconnlistener_set_cb(struct evconnlistener *lev, evconnlistener_cb cb, void *arg);
6.检查evbuffer
/* 这个函数返回 evbuffer 存储的字节数 */
size_t evbuffer_get_length(const struct evbuffer *buf);
7.检查evbuffer
/* 返回连续地存储在 evbuffer前面的字节数(evbuffer中的数据可能存储在多个分隔开的内存块中) */
size_t evbuffer_get_contiguous_space(const struct evbuffer *buf);
8.检测 evconnlistener
/*返回监听器关联的套接字*/
evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);
/*返回event_base*/
struct event_base *evconnlistener_get_base(struct evconnlistener *lev);
9. 向evbuffer添加数据
/* 这个函数添加 data 处的 datalen 字节到 buf 的末尾,成功时返回0,失败时返回-1*/
int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen);
/* 这些函数添加格式化的数据到 buf 末尾 */
int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
// evbuffer_add(buf, "Hello world 2.0.1", 17);
/* 格式参数和其他参数的处理分别与 C 库函数 printf 和 vprintf 相同。函数返回添加的字节数 */
int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap);
// evbuffer_add_printf(buf, "Hello %s %d.%d.%d", "world", 2, 0, 1);
/* 这个函数修改缓冲区的最后一块,或者添加一个新的块,使得缓冲区足以容纳 datlen 字节, 而不需要更多的内存分配。*/
int evbuffer_expand(struct evbuffer *buf, size_t datlen);
10. evbuffer数据移动
/* src 中的所有数据移动到 dst 末尾,成功时返回0,失败时返回-1 */
int evbuffer_add_buffer(struct evbuffer *dst, struct evbuffer *src);
/* 从 src 中移动 datlen 长度字节到 dst 末尾,如果字节数小于 datlen,所有字节被移动。函数返回移动的字节数 */
int evbuffer_remove_buffer(struct evbuffer *src,
struct evbuffer *dst,
size_t datlen);
11. 侦测错误
typedef void (*evconnlistener_errorcb)(struct evconnlistener *lis, void *ptr);
/*监听器设置了错误回调函数,则监听器发生错误 时回调函数就会被调用*/
void evconnlistener_set_error_cb(struct evconnlistener *lev,
evconnlistener_errorcb errorcb);
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步