zoukankan      html  css  js  c++  java
  • (转)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. ", 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. }
  • 相关阅读:
    (深入理解计算机系统)内存对齐
    (深入理解计算机系统)AT&T汇编指令
    (深入理解计算机系统)编译,链接和装载
    (C)struct结构体指针
    (linux)BSP板级支持包开发理解
    TortoiseSVN使用笔记
    (linux)idr(integer ID management)机制
    (linux)struct inode 和 struct file
    cygwin使用笔记
    Zookeeper学习总结
  • 原文地址:https://www.cnblogs.com/buptlyn/p/4253503.html
Copyright © 2011-2022 走看看