evconnlistener机制提供了监听并接受TCP链接的方法。除非特别注明,本章的所有函数和类型都在event2/listener.h中声明。

一:创建或释放evconnlistener

struct evconnlistener  *evconnlistener_new(struct  event_base  *base,

evconnlistener_cb  cb,  void *ptr,  unsigned  flags,  int backlog,

evutil_socket_t  fd);

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);

两个evconnlistener_new*函数都是分配并返回一个新的链接监听器对象。链接监听器使用event_base,在给定监听socket上监听新的TCP链接的到来。当一个新的链接到来时,它调用给定的回调函数。

两个函数中,base参数都是监听器用来监听链接的event_base。cb函数是新链接到来时需要调用的回调函数;如果cb为NULL,则直到设置了回调函数为止,监听器相当于被禁用。ptr指针会传递给回调函数。flag参数控制监听器的行为----详见下方。backlog参数表示在任何时刻,网络栈所允许的等待在“未接受”(not-yet-accepted)状态的挂起链接的最大个数。更多细节参考系统listen函数的手册。如果backlog为负数,则Libevent会自行选择一个比较好的backlog值;如果该值为0,则Libevent认为你已经在给定的socket上调用过listen函数了。

这两个函数的区别在于如何设置监听socket。 evconnlistener_new函数假定已经在希望监听的端口上绑定了socket,也就是fd参数。如果希望Libevent分配并绑定自己的socket,则可以调用evconnlistener_new_bind函数,并且传递一个希望绑定的sockaddr地址及其长度。

注意:使用evconnlistener_new函数时,确定已经通过evutil_make_socket_nonblocking或者手动设置socket选项,将监听socket设置为非阻塞模式。如果监听socket处于阻塞模式,则会有未定义的行为发生。

释放一个链接监听器,调用evconnlistener_free函数。

flags标志位

下面是可以传递给evconnlistener_new函数flags标志,可以使用or运算将任意数量的标志绑定在一起。

LEV_OPT_LEAVE_SOCKETS_BLOCKING:默认情况下,当链接监听器接收一个新的到来的socket时,会将其置为非阻塞状态,从而方便Libevent后续的操作。如果设置了该标志,则会禁止这种行为。

LEV_OPT_CLOSE_ON_FREE:如果设置了该标志,则链接监听器会在释放时关闭底层的socket。

LEV_OPT_CLOSE_ON_EXEC:设置该标志,链接监听器会在底层监听socket上设置“执行时关闭”(close-on-exec)标志。详细信息可以参考操作系统手册中的fcntl和FD_CLOEXEC部分。

LEV_OPT_REUSEABLE:默认情况下在某些平台上,当一个监听socket关闭时,只有经过一定时间之后,其他的socket才能绑定到相同的端口上。设置该标志可以使Libevent标志该socket为可重复使用的,因此一旦它关闭了,则其他socket可以在同一个端口上进行监听。

LEV_OPT_THREADSAFE:为监听器分配锁,因此可以在多线程中安全的使用。

LEV_OPT_DISABLED:将监听器初始化为禁止状态。可以通过函数evconnlistener_enable手动将其使能。

LEV_OPT_DEFERRED_ACCEPT:设置该标志,则告知内核,直到接收到对端数据,并且本地socket准备好读取之前,不通知socket接收新链接。如果网络协议并非以客户端传递数据为开始,则不要使用该标志,因为这样有时会使得内核永远不通知新链接的到来。并非所有系统都支持该标志:在那些不支持的系统上,该标志没有任何作用。

链接监听器的回调函数

typedef void  (*evconnlistener_cb)(struct  evconnlistener  *listener,

evutil_socket_t  sock,  struct sockaddr  *addr,  int len,  void  *ptr);

当新的链接到来时,就会调用回调函数。其中的Listener参数就是接收链接的链接监听器,sock参数就是新的socket本身。addr和len就是链接对端的地址及其长度。ptr就是用户提供的传递给evconnlistener_new函数的参数。

二:将evconnlistener使能和禁止

int  evconnlistener_disable(struct  evconnlistener *lev);

int  evconnlistener_enable(struct  evconnlistener *lev);

这些函数可以将evconnlistener暂时的使能或禁止。

三:调整evconnlistener的回调函数

void  evconnlistener_set_cb(struct  evconnlistener  *lev,

evconnlistener_cb  cb,  void *arg);

该函数改变evconnlistener的回调函数及其参数。

四:监测evconnlistener

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作为第二个参数。

六:例子:回显服务器:

#include <event2/listener.h>

#include <event2/bufferevent.h>

#include <event2/buffer.h>

#include <arpa/inet.h>

#include <string.h>

#include <stdlib.h>

#include <stdio.h>

#include <errno.h>

static void

echo_read_cb(struct bufferevent  *bev,  void *ctx)

{

/* This callback is invoked when thereis data to read on bev. */

struct  evbuffer  *input = bufferevent_get_input(bev);

struct  evbuffer  *output = bufferevent_get_output(bev);

/* Copy all the data from the inputbuffer to the output buffer. */

evbuffer_add_buffer(output,  input);

}

static void

echo_event_cb(struct bufferevent  *bev,  short events,  void  *ctx)

{

if (events & BEV_EVENT_ERROR)

perror("Error frombufferevent");

if (events & (BEV_EVENT_EOF |BEV_EVENT_ERROR)) {

bufferevent_free(bev);

}

}

static void

accept_conn_cb(struct evconnlistener  *listener,

evutil_socket_t  fd,  struct sockaddr  *address,  int  socklen,

void  *ctx)

{

/* We got a new connection! Set up abufferevent for it. */

struct  event_base*base = evconnlistener_get_base(listener);

struct  bufferevent  *bev = bufferevent_socket_new(

base,  fd,  BEV_OPT_CLOSE_ON_FREE);

bufferevent_setcb(bev,  echo_read_cb,  NULL,  echo_event_cb, NULL);

bufferevent_enable(bev,  EV_READ|EV_WRITE);

}

static void

accept_error_cb(struct evconnlistener  *listener,  void  *ctx)

{

struct  event_base  *base = evconnlistener_get_base(listener);

int err = EVUTIL_SOCKET_ERROR();

fprintf(stderr, "Got an error %d(%s) on the listener. "

"Shutting down.\n",err, evutil_socket_error_to_string(err));

event_base_loopexit(base, NULL);

}

int

main(intargc, char **argv)

{

struct  event_base  *base;

struct  evconnlistener  *listener;

struct  sockaddr_in  sin;

int  port = 9876;

if (argc > 1) {

port = atoi(argv[1]);

}

if (port<=0 || port>65535) {

puts("Invalid port");

return 1;

}

base = event_base_new();

if (!base) {

puts("Couldn't open event base");

return 1;

}

/* Clear the sockaddr before using it,in case there are extra

* platform-specific fields that canmess us up. */

memset(&sin ,  0,  sizeof(sin));

/* This is an INET address */

sin.sin_family = AF_INET;

/* Listen on 0.0.0.0 */

sin.sin_addr.s_addr = htonl(0);

/* Listen on the given port. */

sin.sin_port = htons(port);

listener =evconnlistener_new_bind(base,  accept_conn_cb, NULL,

LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,  -1,

(struct sockaddr*)&sin,sizeof(sin));

if (!listener) {

perror("Couldn't createlistener");

return 1;

}

evconnlistener_set_error_cb(listener,  accept_error_cb);

event_base_dispatch(base);

return 0;

}

Lib1vent:10链接监听器接受TCP链接的更多相关文章

  1. socket 关于同一条TCP链接数据包到达顺序的问题

    转:http://blog.csdn.net/l1008610/article/details/52197602 以前作者也一直以为数据包先发的不一定先到,直到今天才意识这个问题的缺陷,数据包是不一定 ...

  2. Nodejs 高并发长链接TCP链接的服务器设计问题

    最近有个项目比较棘手,nodejs的tcp服务,目前的服务器支持3W左右的客户端连接,但是客户希望能够支持30W左右,原先的模型是让客户端请求一个地址分发服务器,然后再tcp链接到不同的地址上实现高并 ...

  3. 网站TCP链接暴增

    昨天上线后,TCP链接暴增,红点增多. 问题在查.其中有一部分,多线程修改,突破了线程数 64的限制.线程内,会发起网络请求. 怀疑是热点之一.其他的部分也有修改,也被怀疑.准备下次,2部分分开上线. ...

  4. ss is one another utility to investigate sockets(特适合大规模tcp链接)

    原创文章,转载请注明: 转载自系统技术非业余研究 本文链接地址: ss is one another utility to investigate sockets(特适合大规模tcp链接) 具体的可以 ...

  5. TCP链接异常断开后,对端仍然ESTABLISH

    双方建立TCP链接,其中一方拔掉网线,另一端依然是ESTABLISHED,那么要过多长时间才会发觉链接被断开了呢? [root@node1 ~]# sysctl -a |grep keepalive ...

  6. TCP链接的三次握手与四次断开

    一直总觉得三次握手和四次断开,之前老师讲的有问题,经过自己再次琢磨,发现是的,老师讲的没毛病,这次也把自己的理解总结一下,让对这个知识模糊的小伙伴再换种思路去理解 首先看一下TCP三次握手发生了哪些: ...

  7. PHP实现新浪长链接转化成短链接API

    我们经常收到类似于这样的短信(如下图),发现其中的链接并不是常规的网址链接,而是个短小精悍的短链接,产品中经常需要这样的需求,如果在给用户下发的短信中是一个很长的连接,用户体验肯定很差,因此我们需要实 ...

  8. 转: linux文件链接(软链接和硬链接)

    链接:一种在共享文件和访问它的用户的若干目录项之间建立联系的一种方法. Linux中包括两种链接:硬链接(Hard Link)和软链接(Soft Link),软链接又称为符号链接(Symbolic l ...

  9. [转]静态库、动态库,dll文件、lib文件,隐式链接、显式链接

    转自:https://blog.csdn.net/dcrmg/article/details/53427181 静态链接.动态链接 静态库和动态库分别应用在静态链接方式和动态链接方式中,所谓静态链接方 ...

随机推荐

  1. 一些hbase的shell查询语句

    华为bids(不想吐槽)种种原因只能用hbase shell查询,在此记录下自己探索的hbase shell 免得下次要用还得去找 scan 'ogg_sel_ioc_sv_product_name_ ...

  2. Ubuntn16.04安装opencv3.1(特别注意环境变量)

    参考:http://lib.csdn.net/article/opencv/25737: http://blog.csdn.net/yiranyhy/article/details/72935499: ...

  3. HDU3486 RMQ

    /*多么变态的一道题,交了18次*/ #include<cstdio> #include<cstring> #include<cmath> #define max( ...

  4. redis异常-MISCONF Redis is configured to save RDB snapshots

     在eclipse中用java代码通过jedis操作redis的时候,报这个错:   redis.clients.jedis.exceptions.JedisDataException: MISCON ...

  5. Oil Deposits HDU - 1241 (dfs)

    Oil Deposits HDU - 1241 The GeoSurvComp geologic survey company is responsible for detecting undergr ...

  6. netbeans7.4 在项目内查找 快捷键 ctrl shift f

  7. top进程命令

    top命令用来显示系统当前的进程状况. 格式:top [选项] 主要选项如下. d:指定更新的间隔,以秒计算. q:没有任何延迟的更新.如果使用者有超级用户,则top命令将会以最高的优先序执行. c: ...

  8. NOIP模拟 17.9.28

    公交车[问题描述]市内有

  9. 阿里云数据管理DMS企业版发布年度重大更新 多项功能全面升级

    随着企业规模和人员扩充,您是否遇到这些问题:企业员工还在使用数据库账号直接操作数据库?人员流动导致运维人员频繁维护数据库账号密码?所有数据库变更还在等DBA集中执行,导致研发效率日益低下. 2月27日 ...

  10. hdu 1251 统计难题(trie树入门)

    统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)Total Submi ...