首页 > 代码库 > (转)Libevent(5)— 连接监听器

(转)Libevent(5)— 连接监听器

转自: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. }

(转)Libevent(5)— 连接监听器