当前位置:   article > 正文

详解Libevent网络库

详解Libevent网络库

项目中要用到libevent,所以就自学了libevent,参考资料为张亮的《libevent源码深度剖析》和《linux高性能服务器编程》

Libevent简介

Libevent是开源社区一款高性能的I/O框架库,其具有如下特点:

1.跨平台支持。Libevent支持Linux、UNIX和Windows。

2.统一事件源。libevent对i/o事件、信号和定时事件提供统一的处理。

3.线程安全。libevent使用libevent_pthreads库来提供线程安全支持。

4.基于reactor模式的实现。

reactor基本知识

reactor是i/o框架库的核心,它主要提供的几个方法是:

1.handle_events:该方法执行事件循环,重复如下过程:等待事件,然后依次处理所有就绪事件对应的时间处理器。

2.register_handler:该方法调用事件多路分发器的register_event方法来往事件多路分发器中注册一个事件。

3.remove_handler:该方法调用事件多路分发器的remove_event方法来删除事件多路分发器中的一个事件。

下图为i/o框架库的工作时序图:



reactor具有如下优点:

1.响应快,不必为单个同步事件所阻塞;

2.编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;

3.可扩展性,可以方便的通过增加reactor实例个数来充分利用CPU资源;

4.可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性。

libevent库的主要逻辑:

1.调用event_init函数创建event_base对象。一个event_base相当于一个reactor实例。

2.创建具体的事件处理器,并设置它们所从属的reactor实例。evsignal_new和evtimer_new分别用于创建信号事件处理器和定时事件处理器,它们的统一入口是event_new函数,event_new函数成功时返回一个event类型的对象,也就是libevent的事件处理器


3.调用event_add函数,将事件处理器添加到注册事件队列中,并将该事件处理器对应的事件添加到事件多路分发器中。

4.调用event_base_dispatch函数来执行事件循环。

5.事件循环结束后,使用*_free系列函数来释放系统资源。

源代码组织结构

1)头文主要就是 event.h:事件宏定义、接口函数声明,主要结构体 event 的声明;


2)内部头文件
xxx-internal.h:内部数据结构和函数,对外不可见,以达到信息隐藏的目的;
3) libevent 框架
event.c: event 整体框架的代码实现;
4)对系统 I/O 多路复用机制的封装
epoll.c:对 epoll 的封装;
select.c:对 select 的封装;
devpoll.c:对 dev/poll 的封装;
kqueue.c:对 kqueue 的封装;
5)定时事件管理
min-heap.h:其实就是一个以时间作为 key 的小根堆结构;
6)信号管理
signal.c:对信号事件的处理;
7)辅助功能函数
evutil.h 和 evutil.c:一些辅助功能函数,包括创建 socket pair 和一些时间操作函数:加、减
和比较等。
8)日志
log.h 和 log.c: log 日志函数
9)缓冲区管理
evbuffer.c 和 buffer.c: libevent 对缓冲区的封装;
10)基本数据结构
compat\sys 下的两个源文件: queue.h 是 libevent 基本数据结构的实现,包括链表,双向链表,
队列等; _libevent_time.h:一些用于时间操作的结构体定义、函数和宏定义;
11)实用网络库


http 和 evdns:是基于 libevent 实现的 http 服务器和异步 dns 查询库;

event结构体

libevent中的事件处理器是event结构类型。event结构体封装了句柄、事件类型、回调函数、以及其他必要的标志和数据,源代码如下

  1. struct event {
  2. TAILQ_ENTRY(event) ev_active_next;
  3. TAILQ_ENTRY(event) ev_next;
  4. /* for managing timeouts */
  5. union {
  6. TAILQ_ENTRY(event) ev_next_with_common_timeout;
  7. int min_heap_idx;
  8. } ev_timeout_pos;
  9. evutil_socket_t ev_fd;
  10. struct event_base *ev_base;
  11. union {
  12. /* used for io events */
  13. struct {
  14. TAILQ_ENTRY(event) ev_io_next;
  15. struct timeval ev_timeout;
  16. } ev_io;
  17. /* used by signal events */
  18. struct {
  19. TAILQ_ENTRY(event) ev_signal_next;
  20. short ev_ncalls;
  21. /* Allows deletes in callback */
  22. short *ev_pncalls;
  23. } ev_signal;
  24. } _ev;
  25. short ev_events;
  26. short ev_res; /* result passed to event callback */
  27. short ev_flags;
  28. ev_uint8_t ev_pri; /* smaller numbers are higher priority */
  29. ev_uint8_t ev_closure;
  30. struct timeval ev_timeout;
  31. /* allows us to adopt for different types of events */
  32. void (*ev_callback)(evutil_socket_t, short, void *arg);
  33. void *ev_arg;
  34. };
ev_active_next: 表示就绪状态的事件链表指针,当关注的事件就绪后,会把
对应的event放入active的队列里。表示该事件在active队列里的位置
ev_next:表示所有事件队列链表的指针。表示该事件在所有时间列表的位置。
ev_timeout_pos:用于管理超时
ev_fd:event绑定的socket描述符
ev_events:
event关注的事件类型,它可以是以下3种类型:
I/O事件: EV_WRITE和EV_READ
定时事件: EV_TIMEOUT
信号: EV_SIGNAL
辅助选项: EV_PERSIST,表明是一个永久事件
Libevent中的定义为:
#define EV_TIMEOUT 0x01
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10 /* Persistant event */
ev_res:记录了当前激活事件的类型;
ev_flags: libevent 用于标记 event 信息的字段,表明其当前的状态,可能的值有:
#define EVLIST_TIMEOUT 0x01 // event在time堆中
#define EVLIST_INSERTED 0x02 // event在已注册事件链表中
#define EVLIST_SIGNAL 0x04 // 未见使用
#define EVLIST_ACTIVE 0x08 // event在激活链表中
#define EVLIST_INTERNAL 0x10 // 内部使用标记
#define EVLIST_INIT 0x80 // event 已被初始化
ev_pri:当前事件的优先级
ev_timeout:超时时间设置
ev_callback:该事件对应的回调函数,和cb类型一样
ev_arg:回调函数用到参数
ev_ncalls:事件就绪执行时,调用 ev_callback 的次数,通常为 1;
ev_pncalls:指针,通常指向 ev_ncalls 或者为 NULL;


往注册事件队列中添加事件处理器

创建一个event对象的函数是event_new,创建好之后应用程序调用event_add函数将其添加到注册事件队列中,并将对应的事件注册到事件多路分发器上,event_add函数主要是调用一个内部函数event_add_internal来实现的。

eventop结构体

eventop结构体封装了i/o复用机制必要的一些操作,比如注册事件、等待事件等,它为event_base支持的所有后端i/o复用机制提供了一个统一的接口,libevent默认选择的后端i/o复用技术是epoll。

event_base结构体

结构体event_base是libevent的reactor,源码如下:

  1. struct event_base {
  2. /** Function pointers and other data to describe this event_base's
  3. * backend. */
  4. const struct eventop *evsel;
  5. /** Pointer to backend-specific data. */
  6. void *evbase;
  7. /** List of changes to tell backend about at next dispatch. Only used
  8. * by the O(1) backends. */
  9. struct event_changelist changelist;
  10. /** Function pointers used to describe the backend that this event_base
  11. * uses for signals */
  12. const struct eventop *evsigsel;
  13. /** Data to implement the common signal handelr code. */
  14. struct evsig_info sig;
  15. /** Number of virtual events */
  16. int virtual_event_count;
  17. /** Number of total events added to this event_base */
  18. int event_count;
  19. /** Number of total events active in this event_base */
  20. int event_count_active;
  21. /** Set if we should terminate the loop once we're done processing
  22. * events. */
  23. int event_gotterm;
  24. /** Set if we should terminate the loop immediately */
  25. int event_break;
  26. /** Set if we should start a new instance of the loop immediately. */
  27. int event_continue;
  28. /** The currently running priority of events */
  29. int event_running_priority;
  30. /** Set if we're running the event_base_loop function, to prevent
  31. * reentrant invocation. */
  32. int running_loop;
  33. /* Active event management. */
  34. /** An array of nactivequeues queues for active events (ones that
  35. * have triggered, and whose callbacks need to be called). Low
  36. * priority numbers are more important, and stall higher ones.
  37. */
  38. struct event_list *activequeues;
  39. /** The length of the activequeues array */
  40. int nactivequeues;
  41. /* common timeout logic */
  42. /** An array of common_timeout_list* for all of the common timeout
  43. * values we know. */
  44. struct common_timeout_list **common_timeout_queues;
  45. /** The number of entries used in common_timeout_queues */
  46. int n_common_timeouts;
  47. /** The total size of common_timeout_queues. */
  48. int n_common_timeouts_allocated;
  49. /** List of defered_cb that are active. We run these after the active
  50. * events. */
  51. struct deferred_cb_queue defer_queue;
  52. /** Mapping from file descriptors to enabled (added) events */
  53. struct event_io_map io;
  54. /** Mapping from signal numbers to enabled (added) events. */
  55. struct event_signal_map sigmap;
  56. /** All events that have been enabled (added) in this event_base */
  57. struct event_list eventqueue;
  58. /** Stored timeval; used to detect when time is running backwards. */
  59. struct timeval event_tv;
  60. /** Priority queue of events with timeouts. */
  61. struct min_heap timeheap;
  62. /** Stored timeval: used to avoid calling gettimeofday/clock_gettime
  63. * too often. */
  64. struct timeval tv_cache;
  65. #if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
  66. /** Difference between internal time (maybe from clock_gettime) and
  67. * gettimeofday. */
  68. struct timeval tv_clock_diff;
  69. /** Second in which we last updated tv_clock_diff, in monotonic time. */
  70. time_t last_updated_clock_diff;
  71. #endif
  72. #ifndef _EVENT_DISABLE_THREAD_SUPPORT
  73. /* threading support */
  74. /** The thread currently running the event_loop for this base */
  75. unsigned long th_owner_id;
  76. /** A lock to prevent conflicting accesses to this event_base */
  77. void *th_base_lock;
  78. /** The event whose callback is executing right now */
  79. struct event *current_event;
  80. /** A condition that gets signalled when we're done processing an
  81. * event with waiters on it. */
  82. void *current_event_cond;
  83. /** Number of threads blocking on current_event_cond. */
  84. int current_event_waiters;
  85. #endif
  86. #ifdef WIN32
  87. /** IOCP support structure, if IOCP is enabled. */
  88. struct event_iocp_port *iocp;
  89. #endif
  90. /** Flags that this base was configured with */
  91. enum event_base_config_flag flags;
  92. /* Notify main thread to wake up break, etc. */
  93. /** True if the base already has a pending notify, and we don't need
  94. * to add any more. */
  95. int is_notify_pending;
  96. /** A socketpair used by some th_notify functions to wake up the main
  97. * thread. */
  98. evutil_socket_t th_notify_fd[2];
  99. /** An event used by some th_notify functions to wake up the main
  100. * thread. */
  101. struct event th_notify;
  102. /** A function used to wake up the main thread from another thread. */
  103. int (*th_notify_fn)(struct event_base *base);
  104. };

事件循环

libevent中实现事件循环的函数是event_base_loop,该函数首先调用i/o事件多路分发器的事件监听函数,以等待事件,当有事件发生时,就依次处理之。

参考博客:点击打开链接


 
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/458453
推荐阅读
相关标签
  

闽ICP备14008679号