Libevent(5)— 连接监听器

系统 1998 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. }

Libevent(5)— 连接监听器


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论