Libevent(5)— 连接监听器

6 篇文章 0 订阅
5 篇文章 0 订阅

转自: 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. // 创建一个新的连接监听器
  14. struct evconnlistener *evconnlistener_new(
  15. struct event_base *base,
  16. // 一个新的连接到来时此回调被调用
  17. evconnlistener_cb cb,
  18. // 用户自定义数据,会被传递给 cb 回调函数
  19. void *ptr,
  20. // 连接监听器的选项(下面会详细谈到)
  21. unsigned flags,
  22. // 为标准的 listen 函数的 backlog 参数
  23. // 如果为负数,Libevent 将尝试选择一个合适的值
  24. int backlog,
  25. // socket
  26. // Libevent 假定此 socket 已经绑定
  27. evutil_socket_t fd
  28. );
  29.  
  30. // 创建一个新的连接监听器
  31. // 大多数参数含义同于 evconnlistener_new
  32. struct evconnlistener *evconnlistener_new_bind(
  33. struct event_base *base,
  34. evconnlistener_cb cb,
  35. void *ptr,
  36. unsigned flags,
  37. int backlog,
  38. // 指定需要绑定的 socket 地址
  39. const struct sockaddr *sa,
  40. int socklen
  41. );

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

  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. // 为连接监听器设置错误回调函数
  5. void evconnlistener_set_error_cb(struct evconnlistener *lev,
  6. evconnlistener_errorcb errorcb);

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值