(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);
posted @ 2023-11-09 21:52  osbreak  阅读(13)  评论(0编辑  收藏  举报