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. php 5.3 iis php_memcache 安装不上

    有的服务器很扯淡,安装了很长时间的php_memcache 扩展 始终安装不上 具体原因不清楚 因为 php_memcache.dll php 官网上只有 最新支持的版本 例如 http://pecl ...

  2. Linux驱动手动绑定和解绑定方法

    linux内核从2.6.13-rc3开始,提供了在用户空间,可动态的绑定和解绑定设备和设备驱动之间关系的功能.在这之前,只能通过insmod(modprobe)和rmmod来绑定和解绑,而且这种绑定和 ...

  3. 【html、CSS、javascript-8】JavaScript作用域

    JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话 一.JavaScript中无块级作用域 在Java或C#中存在块级作用域,即:大括 ...

  4. LUOGU P3435 [POI2006]OKR-Periods of Words

    传送门 解题思路 首先求出kmp,那么i-nxt[i]一定是一个周期,对于每一个点一直跳nxt,跳到最小的nxt之后用i-这个nxt即为i这个前缀的答案. 代码 #include<iostrea ...

  5. 这些Excel学会了,你做账的效率将大大提高

    这些Excel学会了,你做账的效率将大大提高 这些功能学会了,工作效率将大大提高. 1.excel的快速访问工具栏: 我的快速访问工具栏由左到右主要是"保存"."新建&q ...

  6. 【JZOJ5363】【NOIP2017提高A组模拟9.14】生命之树 Trie+启发式合并

    题面 45 在比赛中,我只想到了45分的暴力. 对于一个树中点对,相当于在他们的LCA及其祖先加上这个点对的贡献. 那么这个可以用dfs序+树状数组来维护. 100 想法 我想到了可能要用trie树来 ...

  7. description The request sent by the client was syntactically incorrect.

    shi用url传递参数,其他页面都ojbk的 唯独有一个请求 不应该啊 这明显的已经配置好了啊 因为别的请求我也是这样配置的啊,运行是没问题的啊 运行好好的啊 一时间,感觉无从下手了 经过十几分钟各种 ...

  8. 【Codeforces Round #430 (Div. 2) C】Ilya And The Tree

    [链接]点击打开链接 [题意] 给你一棵n个点的树,每个点的美丽值定义为根节点到这个点的路径上的所有权值的gcd. 现在,假设对于每一个点,在计算美丽值的时候,你可以将某一个点的权值置为0的话. 问你 ...

  9. 关于rss的内容(转载)

    转载自: https://blog.csdn.net/zhao1949/article/details/52806123 (本文对读者有帮助的话请移步支持原作者) 内容记录: 在C++技术网开通了RS ...

  10. 001. 注释过的boot.s

    从网上搜罗一个很详细注释的boot.s版本,加了小小一点点自己的理解,不太多. 用 as86, ld86 可以编译,   ubuntu下可以通过 apt install bin86 来安装好像. ; ...