文章目录
evconnlistener的简介
evconnlistener机制提供了一种监听并接受到来的TCP连接的方法。
所有的函数和类型这里都定义在event2/listener.h中
创建一个evconnlistener
两个函数的不同在于如何建立监听套接字!!
evconnlistener_new()函数假定已经将套接字绑定到要监听的端口,然后通过fd传入这个套接字。
如果要libevent分配和绑定套接字,可以调用 evconnlistener_new_bind(),传输要绑定到的地址和地址长度。
使用evconnlistener_new_bind()的好处:
1、省去了用户手动注册事件的过程。
2、省去了用户去验证系统函数返回是否成功的问题。
3、帮助用户完成了处理非阻塞套接字accpet的麻烦。
1、evconnlistener_new
struct evconnlistener* evconnlistener_new(struct event_base * base,
evconnlistener_cb cb,
void* ptr,
unsigned flags,
int backlog,
evutil_socket_t fd);
当使用evconnlistener_new()的时候务必确认你的监听socket是非阻塞模式。
使用evutil_make_socket_nonblocking或手动设置socket的正确选项。
当监听socket处于阻塞模式,将会导致一些无法预知的行为发生。
2、evconnlistener_new_bind
struct evconnlistener* evconnlistener_new_bind(struct event_base * base,
evconnlistener_cb cb,
void* ptr,
unsigned flags,
int backlog,
const struct sockaddr* sa,
int socklen);
void evconnlistener_free(struct evconnlistener* lev);
两个函数都分配和返回一个新的连接监听器对象。
连接监听器使用event_base来得知什么时候在给定的监听套接字上有新的TCP连接。新连接到达时,监听器调用你给出的回调函数。
两个函数中的参数:
base:都是监听器用于监听连接的event_base。
cb:是收到新连接时要调用的回调函数;如果cb为NULL,则监听器是禁用的,直到设置了回调函数为止。
ptr:指针将传递给回调函数。
flags:控制回调函数的行为,下面会更详细论述。
backlog:是任何时刻网络栈允许处于还未接受状态的最大未决连接数,更多细节请查看系统的listen()函数文档。如果backlog是负的,libevent会试图挑选一个较好的值;如果为0,libevent认为已经对提供的套接字调用了 listen()。
可识别的标志
可以给 evconnlistener_new()函数的flags参数传入一些标志。
可以用或(OR)运算任意连接下述标志:
标志 | 含义 |
---|---|
LEV_OPT_LEAVE_SOCKETS_BLOCKING | 默认情况下,连接监听器接收新套接字后,会将其设置为非阻塞的,以便将其用于libevent 。如果不想要这种行为,可以设置这个标志 |
LEV_OPT_CLOSE_ON_FREE | 如果设置了这个选项,释放连接监听器会关闭底层套接字 |
LEV_OPT_CLOSE_ON_EXEC | 如果设置了这个选项,连接监听器会为底层套接字设置close-on-exec标志。(更多信息请查看fcntl和FD_CLOEXEC的平台文档) |
LEV_OPT_REUSEABLE | 某些平台在默认情况下,关闭某监听套接字后,要过一会儿其他套接字才可以绑定到同一个端口。设置这个标志会让libevent标记套接字是可重用的,这样一旦关闭,可以立即打开其他套接字,在相同端口进行监听。 |
LEV_OPT_THREADSAFE | 为监听器分配锁。这样就可以在多个线程中安全地使用了 |
回调函数的使用
typedef void ( * evconnlistener_cb)(struct evconnlistener* listener,
evutil_socket_t sock,
struct sockaddr* addr,
int len,
void * ptr);
当一个新的连接到来,提供的回调函数将会被调用。
参数作用:
参数listener是用于接受连接的连接监听器
参数sock是新的fd
参数addr和len分别是接受的连接地址和地址的长度
参数ptr是传到evconnlistener_new()的用户提供的指针
要注意的是:
当这个回调函数被调用时,Libevent已经帮我们accept了这个客户端。
所以,该回调函数有一个参数是文件描述符fd。我们直接使用这个fd即可,真是方便。这个参数是可以为NULL的,此时用户并不能接收到客户端。当用户调用evconnlistener_set_cb函数设置回调函数后,就可以了。
释放连接监听器
evconnlistener_free()
void evconnlistener_free(struct evconnlistener* lev);
启用和禁用evconnlistener
int evconnlistener_disable(struct evconnlistener* lev);
int evconnlistener_enable(struct evconnlistener* lev);
这两个函数临时启用或禁用监听新的连接的功能
调整evconnlistener的回调函数
void evconnlistener_set_cb(struct evconnlistener* lev,
evconnlistener_cb cb,
void* arg);
该函数调整已有evconnlistener的回调函数和回调函数参数
检查evconnlistener的event_base和sockfd
evutil_socket_t evconnlistener_get_fd(struct evconnlistener* lev);
struct event_base* evconnlistener_get_base(struct evconnlistener * lev);
这两个函数分别返回了监听器关联的socket和event_base
设置错误回调函数
当在监听器上调用accept()函数调用失败的时候收集错误信息。
在当面临一个不解决就可能锁掉进程的错误条件的时候则显得非常重要
typedef void ( * evconnlistener_errorcb)(struct evconnlistener* lis, void * ptr);
void evconnlistener_set_error_cb(struct evconnlistener* lev,
evconnlistener_errorcb errorcb);
如果调用 evconnlistener_set_error_cb()函数为监听器设置一个错误回调函数,每次监听器出现错误的时候该函数都会返回。
该函数接收监听器作为其第一个参数,传递到evconnlistener_new()接口的参数ptr作为其第二个参数。