转自:http://name5566.com/4220.html

参考文献列表:
http://www.wangafu.net/~nickm/libevent-book/

此文编写的时候,使用到的 Libevent 为 2.0.21

Libevent 提供了连接监听器 evconnlistener

创建 evconnlistener 实例

  1. // 连接监听器回调函数原型
  2. typedef void (*evconnlistener_cb)(
  3. struct evconnlistener *listener,
  4. // 新的 socket
  5. evutil_socket_t sock,
  6. // 新的 socket 对应的地址
  7. struct sockaddr *addr,
  8. int len,
  9. // 用户自定义数据
  10. void *ptr
  11. );
  12. // 创建一个新的连接监听器
  13. struct evconnlistener *evconnlistener_new(
  14. struct event_base *base,
  15. // 一个新的连接到来时此回调被调用
  16. evconnlistener_cb cb,
  17. // 用户自定义数据,会被传递给 cb 回调函数
  18. void *ptr,
  19. // 连接监听器的选项(下面会详细谈到)
  20. unsigned flags,
  21. // 为标准的 listen 函数的 backlog 参数
  22. // 如果为负数,Libevent 将尝试选择一个合适的值
  23. int backlog,
  24. // socket
  25. // Libevent 假定此 socket 已经绑定
  26. evutil_socket_t fd
  27. );
  28. // 创建一个新的连接监听器
  29. // 大多数参数含义同于 evconnlistener_new
  30. struct evconnlistener *evconnlistener_new_bind(
  31. struct event_base *base,
  32. evconnlistener_cb cb,
  33. void *ptr,
  34. unsigned flags,
  35. int backlog,
  36. // 指定需要绑定的 socket 地址
  37. const struct sockaddr *sa,
  38. int socklen
  39. );

连接监听器的常用选项如下:

  1. LEV_OPT_CLOSE_ON_FREE
    当关闭连接监听器其底层 socket 也被自动释放
  2. LEV_OPT_REUSEABLE
    设置 socket 绑定的地址可以重用
  3. LEV_OPT_THREADSAFE
    设置连接监听器为线程安全的

释放连接监听器

  1. void evconnlistener_free(struct evconnlistener *lev);

错误检测
如果连接监听器出错,我们可以得到通知:

  1. // 连接监听器错误回调函数原型
  2. typedef void (*evconnlistener_errorcb)(struct evconnlistener *lis, void *ptr);
  3. // 为连接监听器设置错误回调函数
  4. void evconnlistener_set_error_cb(struct evconnlistener *lev,
  5. evconnlistener_errorcb errorcb);

一个详细的范例(echo 服务器)

    1. #include <event2/listener.h>
    2. #include <event2/bufferevent.h>
    3. #include <event2/buffer.h>
    4. #include <arpa/inet.h>
    5. #include <string.h>
    6. #include <stdlib.h>
    7. #include <stdio.h>
    8. #include <errno.h>
    9. // 读取回调函数
    10. static void
    11. echo_read_cb(struct bufferevent *bev, void *ctx)
    12. {
    13. struct evbuffer *input = bufferevent_get_input(bev);
    14. struct evbuffer *output = bufferevent_get_output(bev);
    15. // 将输入缓冲区的数据直接拷贝到输出缓冲区
    16. evbuffer_add_buffer(output, input);
    17. }
    18. // 事件回调函数
    19. static void
    20. echo_event_cb(struct bufferevent *bev, short events, void *ctx)
    21. {
    22. if (events & BEV_EVENT_ERROR)
    23. perror("Error from bufferevent");
    24. if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
    25. bufferevent_free(bev);
    26. }
    27. }
    28. // 连接监听器回调函数
    29. static void
    30. accept_conn_cb(struct evconnlistener *listener,
    31. evutil_socket_t fd, struct sockaddr *address, int socklen,
    32. void *ctx)
    33. {
    34. // 为新的连接分配并设置 bufferevent
    35. struct event_base *base = evconnlistener_get_base(listener);
    36. struct bufferevent *bev = bufferevent_socket_new(
    37. base, fd, BEV_OPT_CLOSE_ON_FREE);
    38. bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, NULL);
    39. bufferevent_enable(bev, EV_READ|EV_WRITE);
    40. }
    41. // 连接监听器错误回调函数
    42. static void
    43. accept_error_cb(struct evconnlistener *listener, void *ctx)
    44. {
    45. struct event_base *base = evconnlistener_get_base(listener);
    46. // 获取到错误信息
    47. int err = EVUTIL_SOCKET_ERROR();
    48. fprintf(stderr, "Got an error %d (%s) on the listener. "
    49. "Shutting down.\n", err, evutil_socket_error_to_string(err));
    50. // 退出事件循环
    51. event_base_loopexit(base, NULL);
    52. }
    53. int
    54. main(int argc, char **argv)
    55. {
    56. struct event_base *base;
    57. struct evconnlistener *listener;
    58. struct sockaddr_in sin;
    59. int port = 9876;
    60. if (argc > 1) {
    61. port = atoi(argv[1]);
    62. }
    63. if (port<=0 || port>65535) {
    64. puts("Invalid port");
    65. return 1;
    66. }
    67. base = event_base_new();
    68. if (!base) {
    69. puts("Couldn't open event base");
    70. return 1;
    71. }
    72. memset(&sin, 0, sizeof(sin));
    73. sin.sin_family = AF_INET;
    74. sin.sin_addr.s_addr = htonl(0);
    75. sin.sin_port = htons(port);
    76. listener = evconnlistener_new_bind(base, accept_conn_cb, NULL,
    77. LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1,
    78. (struct sockaddr*) & sin, sizeof(sin));
    79. if (!listener) {
    80. perror("Couldn't create listener");
    81. return 1;
    82. }
    83. evconnlistener_set_error_cb(listener, accept_error_cb);
    84. event_base_dispatch(base);
    85. return 0;
    86. }

(转)Libevent(5)— 连接监听器的更多相关文章

  1. libevent系列文章

    Libevent 2 提供了 bufferevent 接口,简化了编程的难度,bufferevent 实际上是对底层事件核心的封装,因此学习 bufferevent 的实现是研究 Libevent 底 ...

  2. 项目中的libevent

    单线程libevent模式 项目里面是多线程版的,我先理解下单线程的. //client .调用NGP::init() bool NGP::init(NGPcontext context) { _co ...

  3. libevent入门

    Libevent API =============================== evtimer_new evtimer_new(base, callback, NULL) 用来做定时器,即当 ...

  4. Libevent API

    evtimer_new evtimer_new(base, callback, NULL) 用来做定时器,即当达到一定时间后调用回调函数callback.用evtimer_add激活定时器.比如: m ...

  5. Libevent官方代码样例学习(二)

    连接监听器: 接收TCP连接请求 evconnlistener机制用于监听并接受TCP连接请求. 这些方法在event2/listener.h中声明, 在Libevent 2.0.2-alpha之后的 ...

  6. libevent编程疑难解答

    http://blog.csdn.net/luotuo44/article/details/39547391 转载请注明出处:http://blog.csdn.net/luotuo44/article ...

  7. Oracle 监听器

    Oracle监听器listener是一个重要的数据库服务器组件,在整个Oracle体系结构中,扮演着重要的作用. 监听器Lisener功能 从当前的Oracle版本看,Listener主要负责下面的几 ...

  8. Android基于XMPP Smack Openfire下学习开发IM(五)连接断开重连

    学习过程中大家都碰到过连接被断开的问题给困扰吧,下面教大家如何做到连接断开后,重新连接 首先要创建连接监听器,用来监听连接状态,这里我写了一个类 继承了ConnectionListener,重写了里面 ...

  9. Openfire分析之三:ConnectionManager 连接管理(1)

    Openfire是怎么实现连接请求的? XMPPServer.start()方法,完成Openfire的启动.但是,XMPPServer.start()方法中,并没有提及如何监听端口,那么Openfi ...

随机推荐

  1. Kooboo中主要的几个关键词中的关系

    Kooboo中主要的几个关键词中的关系 Content Type  //相当于数据库表 Content      //相当于数据 View         //部分View 她可以使用Content ...

  2. puppet_list

  3. 成都Uber优步司机奖励政策(2月6日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  4. oralce health monitor

    1. Health Monitor简介    Health Monitor是11g里新增加的特性,用于数据库的各层和各个组建的诊断检查.例如可以检查:文件损坏.物理逻辑块损坏.redo和undo故障. ...

  5. JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  6. cocos2d-x 绘制基本图元

    转自:http://4137613.blog.51cto.com/4127613/754729 第一部分:基本图形绘制   cocos2dx封装了大量opengl函数,用于快速绘制基本图形,这些代码的 ...

  7. matlab2013a for linux/Ubuntu 安装步骤及创建快捷方式(ubuntu14.04下安装)

    1.挂载安装镜像:sudo mount -o loop myfile.iso /media/mnt   #挂载ISO文件,使用參数 -o loop      mnt为已经建立好的文件夹. 2.运行安装 ...

  8. [React Native] Passing data when changing routes

    The way you make HTTP requests in React Native is with the Fetch API. In this video we'll talk about ...

  9. iOS 数组越界 Crash加工经验

    我们先来看看有可能会出现的数组越界Crash的地方. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSInd ...

  10. Android5.0常用颜色属性说明

    在使用Eclipse的时代,我们很少去在style文件给整个应用或者Activity去设定颜色,那是因为即使设置也不会提升用户的视觉效果.但是材料设计号称让没有设计功底的人也能做出漂亮的App,那我们 ...