码迷,mamicode.com
首页 > 其他好文 > 详细

Libevent分析

时间:2015-10-18 18:09:13      阅读:271      评论:0      收藏:0      [点我收藏+]

标签:

一、使用举例

一个简单的使用libevent创建的echosvr如下:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <unistd.h>
  5 #include <arpa/inet.h>
  6 #include <netinet/in.h>
  7 #include <sys/epoll.h>
  8 #include <sys/types.h>       
  9 #include <sys/socket.h>
 10 #include <errno.h>
 11 #include <event.h>
 12 #include "dlist.h"
 13 
 14 #define BUF_SIZE    1024
 15 char buf[BUF_SIZE];
 16 
 17 void on_accept(int sock, short event, void* arg);
 18 void on_read(int sock, short event, void* arg);
 19 
 20 struct event_list
 21 {
 22     struct event ev;
 23     struct list_head list;
 24 };
 25 
 26 struct event_list evlist;
 27 struct event_base* evbase = NULL;
 28 
 29 int main(void)
 30 {
 31     int listenfd = -1;
 32     struct sockaddr_in svraddr;
 33     int nready = 0;
 34     int i = 0;
 35     INIT_LIST_HEAD(&evlist.list); 
 36     
 37     if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 38     {
 39         perror("socket error");
 40         return -1;
 41     }
 42 
 43     memset(&svraddr, 0, sizeof(svraddr));
 44     svraddr.sin_family = AF_INET;
 45     svraddr.sin_port = htons(44888);
 46     svraddr.sin_addr.s_addr = htonl(INADDR_ANY);
 47 
 48     if (bind(listenfd, (struct sockaddr* )&svraddr, sizeof(svraddr)) < 0)
 49     {
 50         perror("bind error");
 51         return -1;
 52     }
 53 
 54     if (listen(listenfd, 5) < 0)
 55     {
 56         perror("listen error");
 57         return -1;
 58     }
 59         
 60     evbase = event_base_new();
 61     struct event_list* evlisten = (struct event_list* )malloc(sizeof(struct event_list));
 62     list_add_tail(&(evlisten->list), &(evlist.list));
 63     event_set(&(evlisten->ev), listenfd, EV_READ | EV_PERSIST, on_accept, (void* )evbase);
 64     event_base_set(evbase, &(evlisten->ev));
 65     event_add(&(evlisten->ev), NULL);
 66 
 67     event_base_dispatch(evbase);
 68     printf("The End.\n");
 69 
 70     return 0;
 71 }
 72 
 73 void on_accept(int sock, short event, void* arg)
 74 {
 75     int fd;
 76     struct event_base* evbase = (struct event_base* )arg;
 77     struct sockaddr_in cliaddr;
 78     uint32_t slen = sizeof(cliaddr);
 79     fd = accept(sock, (struct sockaddr* )&cliaddr, &slen);
 80     if (fd < 0)
 81     {
 82         perror("accept");
 83         return;
 84     }
 85     printf("recv sock %d: <%s:%d>\n", fd, inet_ntoa(cliaddr.sin_addr), htons(cliaddr.sin_port));
 86 
 87     struct event_list* evread = (struct event_list* )malloc(sizeof(struct event_list));
 88     event_set(&(evread->ev), fd, EV_READ | EV_PERSIST, on_read, (void* )evread);
 89     event_base_set(evbase, &(evread->ev));
 90     event_add(&(evread->ev), NULL);
 91 }
 92 
 93 void on_read(int sock, short event, void* arg)
 94 {
 95     int rsize = 0;
 96     memset(buf, 0, BUF_SIZE);
 97     rsize = read(sock, buf, BUF_SIZE);
 98     if (rsize <= 0)
 99     {
100         if (rsize == 0)
101         {
102             printf("client %d close socket.\n", sock);
103         }
104         else
105         {
106             perror("read:");
107         }
108         close(sock);
109         event_del((struct event* )arg);
110         free((struct event* )arg);
111         return;
112     }
113     printf("recv:%s\n", buf);
114     write(sock, buf, strlen(buf));
115     printf("send:%s\n", buf);
116 }

其中使用了双链表来管理events,相关代码如下:

技术分享
  1 #ifndef _LIST_HEAD_H
  2 #define _LIST_HEAD_H
  3 
  4 // 双向链表节点
  5 struct list_head {
  6     struct list_head *next, *prev;
  7 };
  8 
  9 // 初始化节点:设置name节点的前继节点和后继节点都是指向name本身。
 10 #define LIST_HEAD_INIT(name) { &(name), &(name) }
 11 
 12 // 定义表头(节点):新建双向链表表头name,并设置name的前继节点和后继节点都是指向name本身。
 13 #define LIST_HEAD(name)  14     struct list_head name = LIST_HEAD_INIT(name)
 15 
 16 // 初始化节点:将list节点的前继节点和后继节点都是指向list本身。
 17 static inline void INIT_LIST_HEAD(struct list_head *list)
 18 {
 19     list->next = list;
 20     list->prev = list;
 21 }
 22 
 23 // 添加节点:将new插入到prev和next之间。
 24 static inline void __list_add(struct list_head *new,
 25                   struct list_head *prev,
 26                   struct list_head *next)
 27 {
 28     next->prev = new;
 29     new->next = next;
 30     new->prev = prev;
 31     prev->next = new;
 32 }
 33 
 34 // 添加new节点:将new添加到head之后,是new称为head的后继节点。
 35 static inline void list_add(struct list_head *new, struct list_head *head)
 36 {
 37     __list_add(new, head, head->next);
 38 }
 39 
 40 // 添加new节点:将new添加到head之前,即将new添加到双链表的末尾。
 41 static inline void list_add_tail(struct list_head *new, struct list_head *head)
 42 {
 43     __list_add(new, head->prev, head);
 44 }
 45 
 46 // 从双链表中删除entry节点。
 47 static inline void __list_del(struct list_head * prev, struct list_head * next)
 48 {
 49     next->prev = prev;
 50     prev->next = next;
 51 }
 52 
 53 // 从双链表中删除entry节点。
 54 static inline void list_del(struct list_head *entry)
 55 {
 56     __list_del(entry->prev, entry->next);
 57 }
 58 
 59 // 从双链表中删除entry节点。
 60 static inline void __list_del_entry(struct list_head *entry)
 61 {
 62     __list_del(entry->prev, entry->next);
 63 }
 64 
 65 // 从双链表中删除entry节点,并将entry节点的前继节点和后继节点都指向entry本身。
 66 static inline void list_del_init(struct list_head *entry)
 67 {
 68     __list_del_entry(entry);
 69     INIT_LIST_HEAD(entry);
 70 }
 71 
 72 // 用new节点取代old节点
 73 static inline void list_replace(struct list_head *old,
 74                 struct list_head *new)
 75 {
 76     new->next = old->next;
 77     new->next->prev = new;
 78     new->prev = old->prev;
 79     new->prev->next = new;
 80 }
 81 
 82 // 双链表是否为空
 83 static inline int list_empty(const struct list_head *head)
 84 {
 85     return head->next == head;
 86 }
 87 
 88 // 获取"MEMBER成员"在"结构体TYPE"中的位置偏移
 89 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 90 
 91 // 根据"结构体(type)变量"中的"域成员变量(member)的指针(ptr)"来获取指向整个结构体变量的指针
 92 #define container_of(ptr, type, member) ({           93     const typeof( ((type *)0)->member ) *__mptr = (ptr);     94     (type *)( (char *)__mptr - offsetof(type,member) );})
 95 
 96 // 遍历双向链表
 97 #define list_for_each(pos, head)  98     for (pos = (head)->next; pos != (head); pos = pos->next)
 99 
100 #define list_for_each_safe(pos, n, head) 101     for (pos = (head)->next, n = pos->next; pos != (head); 102         pos = n, n = pos->next)
103 
104 #define list_entry(ptr, type, member) 105     container_of(ptr, type, member)
106 
107 #endif
View Code

echosvr的代码流程:

1、经典的使用socket创建tcp socket。

2、创建event base:evbase = event_base_new();

3、创建listen event并加入到eventbase中:

    event_set(&(evlisten->ev), listenfd, EV_READ | EV_PERSIST, on_accept, (void* )evbase);
    event_base_set(evbase, &(evlisten->ev));
    event_add(&(evlisten->ev), NULL);

 

二、Libevent基本数据结构

1、struct event_base (事件处理框架结构)

 1 struct event_base 
 2 {
 3     const struct eventop *evsel;    // IO复用函数集, Linux下一般是epoll的封装
 4     void *evbase;
 5     int event_count;        /* counts number of total events */
 6     int event_count_active;    /* counts number of active events */
 7 
 8     int event_gotterm;        /* Set to terminate loop */
 9     int event_break;        /* Set to terminate loop immediately */
10 
11     /* active event management */
12     struct event_list **activequeues;
13     int nactivequeues;
14 
15     /* signal handling info */
16     struct evsignal_info sig;
17 
18     struct event_list eventqueue;    // 注册事件队列
19     struct timeval event_tv;
20 
21     struct min_heap timeheap;        // 管理定时器小根堆
22 
23     struct timeval tv_cache;        // 记录时间缓存
24 };

evsel:libevent支持Linux、Windows等多种平台,也支持epoll、poll、select、kqueue等多种I/O多路复用模型。evsel会指向

/* In order of preference */
static const struct eventop *eventops[] = {
#ifdef HAVE_EVENT_PORTS
    &evportops,
#endif
#ifdef HAVE_WORKING_KQUEUE
    &kqops,
#endif
#ifdef HAVE_EPOLL
    &epollops,
#endif
#ifdef HAVE_DEVPOLL
    &devpollops,
#endif
#ifdef HAVE_POLL
    &pollops,
#endif
#ifdef HAVE_SELECT
    &selectops,
#endif
#ifdef WIN32
    &win32ops,
#endif
    NULL
};

linux下会指向epollops。

2、struct event(代表一个事件)

 1 struct event 
 2 {
 3     TAILQ_ENTRY (event) ev_next;            // 已注册事件
 4     TAILQ_ENTRY (event) ev_active_next;     // 就绪事件
 5     TAILQ_ENTRY (event) ev_signal_next;        // 信号
 6     unsigned int min_heap_idx;    /* for managing timeouts */
 7 
 8     struct event_base *ev_base;
 9 
10     int ev_fd;                // 对于I/O事件,是绑定的文件描述符
11     short ev_events;        // event关注的事件类型
12     short ev_ncalls;        // 事件就绪执行时,调用 ev_callback 的次数
13     short *ev_pncalls;    /* Allows deletes in callback */
14 
15     struct timeval ev_timeout;    // timout事件的超时值
16 
17     int ev_pri;        /* smaller numbers are higher priority */
18 
19     void (*ev_callback)(int, short, void *arg);    // 回调函数
20     void *ev_arg;                                // 回调函数的参数
21 
22     int ev_res;        /* result passed to event callback */
23     int ev_flags;                                // event的状态
24 };

1) )ev_next,ev_active_next 和 ev_signal_next 都是双向链表节点指针, 定义如下:

1 #define TAILQ_ENTRY(type)                        2 struct {                                3     struct type *tqe_next;    /* next element */            4     struct type **tqe_prev;    /* address of previous next element */    5 }

2) ev_events:event关注的事件类型,它可以是以下3种类型: 
I/O事件: EV_WRITE和EV_READ 
定时事件:EV_TIMEOUT 
信号:    EV_SIGNAL 
辅助选项:EV_PERSIST,表明是一个永久事件

 

Libevent分析

标签:

原文地址:http://www.cnblogs.com/ym65536/p/4889484.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!