Libevent源码阅读——概述、实践

重新读下Libevent的源码,使用最新的Libevent版本libevent-release-2.1.8-stable

Reactor模式简介

Reactor模型
Reactor模式要求主线程(I/O处理单元)只监听文件描述符上是否有事件发生,有的话立即将事件通知工作线程(逻辑单元),除此之外,主线程不进行任何其它实质性的工作,读写数据、接收新的连接、处理客户请求均在工作线程中进行.
使用同步I/O模型(以epoll_wait为例)实现的Reactor模式的工作流程:

  1. 主线程往epoll内核事件表中注册socket上的读就绪事件
  2. 主线程调用epoll_wait等待socket上的读就绪事件
  3. 当socket上有数据可读时,epoll_wait通知主线程.主线程将socket可读事件放入请求队列
  4. 睡眠在请求队列上的的某个工作线程被唤醒,从socket读取数据,并处理客户端请求,然后往epoll内核事件表注册该socket上的写就绪事件
  5. 主线程调用epoll_wait等待socket可写
  6. 当socket可写时,epoll_wait通知主线程.主线程将socket可写事件放入请求队列
  7. 睡眠在请求队列上的某个工作线程被唤醒,往socket上写入服务器处理客户端的结果

更多Reactor介绍请点击

Libevent简介

Libevent是一个使用C语言编写的、轻量级的开源高性能事件通知库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue、IOCP等系统调用管理事件机制。

Libevent特点

  1. 事件驱动、高性能
  2. 轻量级、专注于网络
  3. 开源,代码精炼、易读
  4. 跨平台,支持Windows、Linux、BSD和Mac OS
  5. 支持多路I/O复用技术(epoll、poll、dev/poll、select和kqueue等),在不同操作系统下,做了多路复用模型的抽象,可以使用不同的模型,通过事件函数提供服务
  6. 支持I/O、定时器和信号等事件
  7. 采用Reactor模式
  8. 支持多线程

Libevent源码获取

1
git clone https://github.com/libevent/libevent.git

编译、安装详情请参考官方文档,大致过程如下

1
2
3
4
5
./autogen.sh
./configure
make
make verify # (optional)
sudo make install

执行autogen.sh报错possibly undefined macro: AC_PROG_LIBTOOL安装libtool即可

1
sudo yum install libtool

Libevent功能

  1. 事件通知:当文件描述符可读可写时将执行回调函数
  2. IO缓存:缓存事件提供了输入输出缓存,能自动的读入和写入,用户不必直接操作IO
  3. 定时器:libevent提供定时器机制,能在一定事件间隔后调用回调函数
  4. 信号:触发信号,执行回调
  5. 异步DNS解析:libevent提供异步解析DNS服务器的DNS解析函数集
  6. 事件驱动的http服务器:libevent提供简单的、可集成到引用程序中的HTTP服务器
  7. RPC客户端服务器框架:libevent为创建RPC服务器和客户端创建了一个RPC框架,能自动封装和解封数据结构

Libevent组件

  1. evutil:用来抽象不同平台网络实现差异的通用功能。
  2. event和event_base:libevent的核心,为各种平台特定的、基于事件的非阻塞IO后端提供抽象API,让程序可以知道套接字何时准备好,可以读或者写,并且处理基本的超时事件,检测OS信号。
  3. bufferevent:为libevent基于事件的核心提供使用更方便的封装。除了通知程序套接字已经准备好读写之外,还让程序可以请求缓冲的读写操作,可以知道何时IO已经真正发生。(bufferevent接口有多个后端,可以采用系统能够提供的更快的非阻塞IO方式,如Windows中的IOCP。)
  4. evbuffer:在bufferevent层之下实现缓冲功能,并且提供方便有效的访问函数。
  5. evhttp:一个简单的HTTP客户端/服务器实现。
  6. evdns:一个简单DNS客户端/服务器实现。
  7. evrpc:一个简单RPC实现。

Libevent库

安装libevent时,默认安装下列库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[CaseZheng@localhost Blog]$ ll /usr/local/lib/libevent*
-rw-r--r--. 1 root root 470890 9月 30 23:02 /usr/local/lib/libevent.a
-rw-r--r--. 1 root root 299550 9月 30 23:02 /usr/local/lib/libevent_core.a
lrwxrwxrwx. 1 root root 22 9月 30 23:04 /usr/local/lib/libevent_core.so -> libevent_core.so.2.2.0
-rwxr-xr-x. 1 root root 217848 9月 30 23:02 /usr/local/lib/libevent_core.so.2.2.0
-rw-r--r--. 1 root root 171474 9月 30 23:02 /usr/local/lib/libevent_extra.a
lrwxrwxrwx. 1 root root 23 9月 30 23:04 /usr/local/lib/libevent_extra.so -> libevent_extra.so.2.2.0
-rwxr-xr-x. 1 root root 149576 9月 30 23:02 /usr/local/lib/libevent_extra.so.2.2.0
-rw-r--r--. 1 root root 26152 9月 30 23:02 /usr/local/lib/libevent_openssl.a
lrwxrwxrwx. 1 root root 25 9月 30 23:04 /usr/local/lib/libevent_openssl.so -> libevent_openssl.so.2.2.0
-rwxr-xr-x. 1 root root 35240 9月 30 23:02 /usr/local/lib/libevent_openssl.so.2.2.0
-rw-r--r--. 1 root root 4968 9月 30 23:02 /usr/local/lib/libevent_pthreads.a
lrwxrwxrwx. 1 root root 26 9月 30 23:04 /usr/local/lib/libevent_pthreads.so -> libevent_pthreads.so.2.2.0
-rwxr-xr-x. 1 root root 13600 9月 30 23:02 /usr/local/lib/libevent_pthreads.so.2.2.0
lrwxrwxrwx. 1 root root 17 9月 30 23:04 /usr/local/lib/libevent.so -> libevent.so.2.2.0
-rwxr-xr-x. 1 root root 346224 9月 30 23:02 /usr/local/lib/libevent.so.2.2.0

  1. libevent_core:所有核心的事件和缓存功能,包括所有的event_base、evbuffer、bufferevent和工具函数。
  2. libevent_extra:定义程序可能需要,也可能不需要的协议特定功能,包括HTTP、DNS和RPC。
  3. libevent:历史原因而存在,包括libevent_core和libevent_extra。
  4. libevent_pthreads:添加基于pthread可移植线程库的线程和锁定实现,独立于libevent_core。
  5. libevent_openssl:为使用bufferevent和OpenSSL进行加密的通信提供支持, 独立于libevent_core。

Libevent头文件

libevent公用头文件安装在event2目录中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[CaseZheng@localhost /]$ ll /usr/local/include/event2/
总用量 408
-rw-r--r--. 1 root root 4700 9月 30 22:58 buffer_compat.h
-rw-r--r--. 1 root root 4538 9月 30 22:58 bufferevent_compat.h
-rw-r--r--. 1 root root 34518 9月 30 22:58 bufferevent.h
-rw-r--r--. 1 root root 4848 9月 30 22:58 bufferevent_ssl.h
-rw-r--r--. 1 root root 4135 9月 30 22:58 bufferevent_struct.h
-rw-r--r--. 1 root root 39078 9月 30 22:58 buffer.h
-rw-r--r--. 1 root root 12588 9月 30 22:58 dns_compat.h
-rw-r--r--. 1 root root 26873 9月 30 22:58 dns.h
-rw-r--r--. 1 root root 2596 9月 30 22:58 dns_struct.h
-rw-r--r--. 1 root root 7639 9月 30 22:58 event_compat.h
-rw-r--r--. 1 root root 15740 9月 30 23:02 event-config.h
-rw-r--r--. 1 root root 62445 9月 30 22:58 event.h
-rw-r--r--. 1 root root 5024 9月 30 22:58 event_struct.h
-rw-r--r--. 1 root root 3265 9月 30 22:58 http_compat.h
-rw-r--r--. 1 root root 42821 9月 30 22:58 http.h
-rw-r--r--. 1 root root 4809 9月 30 22:58 http_struct.h
-rw-r--r--. 1 root root 2603 9月 30 22:58 keyvalq_struct.h
-rw-r--r--. 1 root root 7445 9月 30 22:58 listener.h
-rw-r--r--. 1 root root 2351 9月 30 22:58 rpc_compat.h
-rw-r--r--. 1 root root 21702 9月 30 22:58 rpc.h
-rw-r--r--. 1 root root 3235 9月 30 22:58 rpc_struct.h
-rw-r--r--. 1 root root 2141 9月 30 22:58 tag_compat.h
-rw-r--r--. 1 root root 4914 9月 30 22:58 tag.h
-rw-r--r--. 1 root root 9952 9月 30 22:58 thread.h
-rw-r--r--. 1 root root 28536 9月 30 22:58 util.h
-rw-r--r--. 1 root root 2818 9月 30 22:58 visibility.h
  1. API头文件:定义libevent公用接口。
  2. 兼容头文件:已废弃的函数提供兼容的头部包含定义。不应该使用这类头文件。
  3. 结构头文件:以”_struct”为后缀,定义各种结构体,为了快速访问而暴露,或因为历史原因而暴露。不要直接依赖这类头文件中的任何结构体,会破坏对其他版本libevent的二进制兼容性。

简单的定时器和信号事件示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>
#include <cstring>
#include <sys/signal.h>
#include <event2/event.h>
#include <event2/util.h>

using namespace std;

struct timeval lasttime;

static void timeout_cb(evutil_socket_t fd, short events, void *arg)
{
struct timeval newtime, difference;
struct event *timeout = (struct event*)arg;
double elapsed;
evutil_gettimeofday(&newtime, NULL);
evutil_timersub(&newtime, &lasttime, &difference);
elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6);
cout<<"timeout_cb called at "<<newtime.tv_sec<<": "<<elapsed<<"second elapsed"<<endl;
lasttime = newtime;
}

static void signal_cb(evutil_socket_t fd, short events, void *arg)
{
struct event_base *base = (struct event_base *)arg;
struct timeval delay = {1, 0};

cout<<"1 s after exit"<<endl;

event_base_loopexit(base, &delay);
}

int main()
{
struct event_base *base = event_base_new();
if(NULL == base)
{
cout<<"event_base_new error"<<endl;
cout<<strerror(errno)<<endl;
return 0;
}

struct event *signalevent = evsignal_new(base, SIGINT, signal_cb, (void*)base);
event_add(signalevent, NULL);

struct event *timeout_event = evtimer_new(base, timeout_cb, NULL);
//flags设置为EV_PERSIST表示该事件一直有效
int flags = EV_PERSIST;
//flags设置为0,该事件触发一次就会被删除,需要再次添加
//int flags = 0;
event_assign(timeout_event, base, -1, flags, timeout_cb, (void*) timeout_event);

struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = 2;
event_add(timeout_event, &tv);

evutil_gettimeofday(&lasttime, NULL);

event_base_dispatch(base);
event_free(signalevent);
event_free(timeout_event);
event_base_free(base);

return 0;
}

简单的回显服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include <cstring>
#include <unistd.h>

#include <event2/event.h>
#include <event2/listener.h>
#include <event2/util.h>

using namespace std;

void accept_cb(int fd, short events, void *arg);
void socket_read_cb(int fd, short events, void *arg);
int tcp_server_init(int port, int listen_num);

int main()
{
int listener = tcp_server_init(9999, 5);
if(listener == -1)
{
cout<<"tcp_server_init error"<<endl;
return 0;
}

struct event_base * base = event_base_new();
if(NULL == base)
{
cout<<"event_base_new error"<<endl;
return 0;
}

struct event * ev_listen = event_new(base, listener, EV_READ|EV_PERSIST, accept_cb, base);
if(NULL == ev_listen)
{
cout<<"event_new error"<<endl;
return 0;
}
event_add(ev_listen, NULL);

event_base_dispatch(base);

event_free(ev_listen);
return 0;
}

void accept_cb(int fd, short evnets, void *arg)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);

evutil_socket_t sockfd = ::accept(fd, (struct sockaddr*)&client, &len);
if(sockfd < 0)
{
cout<<"accept error"<<endl;
return;
}
evutil_make_socket_nonblocking(sockfd);

cout<<"accpet a conn fd: "<<sockfd<<endl;
struct event_base *base = (struct event_base*)arg;
struct event *ev = event_new(NULL, -1, 0, NULL, NULL);
event_assign(ev, base, sockfd, EV_READ|EV_PERSIST, socket_read_cb, (void*)ev);
event_add(ev, NULL);
}

void socket_read_cb(int fd, short events, void *arg)
{
char buff[4096] = {0};
struct event *ev = (struct event*)arg;
int len = read(fd, buff, sizeof(buff)-1);
if(len <= 0)
{
cout<<"read error len: "<<len<<endl;
event_free(ev);
close(fd);
return;
}
buff[len] = '\0';
cout<<"read msg : "<<buff<<endl;

write(fd, buff, strlen(buff));
}

int tcp_server_init(int port, int listen_num)
{
evutil_socket_t listener;
listener = ::socket(AF_INET, SOCK_STREAM, 0);
if(listener < 0)
{
cout<<"create socket error"<<endl;
return -1;
}

evutil_make_listen_socket_reuseable(listener);

struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(port);
if(::bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
cout<<"bind error"<<endl;
return -1;
}
if(::listen(listener, listen_num) < 0)
{
cout<<"listen error"<<endl;
return -1;
}

evutil_make_socket_nonblocking(listener);

return listener;
}

使用bufferevent的回显服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <iostream>
#include <cstring>
#include <unistd.h>

#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <event2/util.h>

using namespace std;

void accept_cb(int fd, short events, void *arg);
void socket_read_cb(struct bufferevent *bev, void *arg);
void event_cb(struct bufferevent *bev, short event, void *arg);
int tcp_server_init(int port, int listen_num);

int main()
{
int listener = tcp_server_init(9999, 5);
if(listener == -1)
{
cout<<"tcp_server_init error"<<endl;
return 0;
}

struct event_base * base = event_base_new();
if(NULL == base)
{
cout<<"event_base_new error"<<endl;
return 0;
}

struct event * ev_listen = event_new(base, listener, EV_READ|EV_PERSIST, accept_cb, base);
if(NULL == ev_listen)
{
cout<<"event_new error"<<endl;
return 0;
}
event_add(ev_listen, NULL);

event_base_dispatch(base);

event_free(ev_listen);
event_base_free(base);
return 0;
}

void accept_cb(int fd, short evnets, void *arg)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);

evutil_socket_t sockfd = ::accept(fd, (struct sockaddr*)&client, &len);
if(sockfd < 0)
{
cout<<"accept error"<<endl;
return;
}
evutil_make_socket_nonblocking(sockfd);

cout<<"accpet a conn fd: "<<sockfd<<endl;
struct event_base *base = (struct event_base*)arg;

bufferevent *bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE);
if(NULL == bev)
{
cout<<"bufferevent_socket_new error"<<endl;
close(fd);
return;
}
bufferevent_setcb(bev, socket_read_cb, NULL, event_cb, arg);
bufferevent_enable(bev, EV_READ | EV_PERSIST);
}

void socket_read_cb(bufferevent *bev, void *arg)
{
char buff[4096] = {0};
size_t len = bufferevent_read(bev, buff, sizeof(buff));
if(len <= 0)
{
cout<<"read error len: "<<len<<endl;
return;
}
buff[len] = '\0';
cout<<"read msg : "<<buff<<endl;

bufferevent_write(bev, buff, strlen(buff));
}

void event_cb(struct bufferevent *bev, short event, void *arg)
{
if(event & BEV_EVENT_EOF)
{
cout<<"conn close"<<endl;
}
else if(event &BEV_EVENT_ERROR)
{
cout<<"conn error"<<endl;
}
else
{
cout<<"event :"<<event<<endl;
}

bufferevent_free(bev);
}

int tcp_server_init(int port, int listen_num)
{
evutil_socket_t listener;
listener = ::socket(AF_INET, SOCK_STREAM, 0);
if(listener < 0)
{
cout<<"create socket error"<<endl;
return -1;
}

evutil_make_listen_socket_reuseable(listener);

struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(port);
if(::bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
cout<<"bind error"<<endl;
return -1;
}
if(::listen(listener, listen_num) < 0)
{
cout<<"listen error"<<endl;
return -1;
}

evutil_make_socket_nonblocking(listener);

return listener;
}

使用evconnlistener的服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
#include <cstring>
#include <unistd.h>

#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <event2/util.h>

using namespace std;

void accept_cb(evconnlistener *listener, evutil_socket_t fd, \
struct sockaddr *sock, int socklen, void *arg);
void socket_read_cb(struct bufferevent *bev, void *arg);
void event_cb(struct bufferevent *bev, short event, void *arg);

int main()
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(9999);

event_base *base = event_base_new();

evconnlistener * listener = evconnlistener_new_bind(base, accept_cb, \
base, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, \
10, (struct sockaddr*)&sin, \
sizeof(struct sockaddr_in));

event_base_dispatch(base);

evconnlistener_free(listener);
event_base_free(base);

return 0;
}

void accept_cb(evconnlistener *listener, evutil_socket_t fd, \
struct sockaddr *sock, int socklen, void *arg)
{
cout<<"accept a client fd: "<<fd<<endl;

event_base *base = (event_base*)arg;

bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if(NULL == bev)
{
cout<<"bufferevent_socket_new error"<<endl;
close(fd);
return;
}
bufferevent_setcb(bev, socket_read_cb, NULL, event_cb, arg);
bufferevent_enable(bev, EV_READ | EV_PERSIST);
}

void socket_read_cb(bufferevent *bev, void *arg)
{
char buff[4096] = {0};
size_t len = bufferevent_read(bev, buff, sizeof(buff));
if(len <= 0)
{
cout<<"read error len: "<<len<<endl;
return;
}
buff[len] = '\0';
cout<<"read msg : "<<buff<<endl;

bufferevent_write(bev, buff, strlen(buff));
}

void event_cb(struct bufferevent *bev, short event, void *arg)
{
if(event & BEV_EVENT_EOF)
{
cout<<"conn close"<<endl;
}
else if(event &BEV_EVENT_ERROR)
{
cout<<"conn error"<<endl;
}
else
{
cout<<"event :"<<event<<endl;
}

bufferevent_free(bev);
}

Libevent DNS客户端的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <cstring>

#include <event2/event.h>
#include <event2/dns.h>

using namespace std;


void callback(int errcode, struct evutil_addrinfo *addr, void *ptr)
{
if (errcode)
{
cout<<"error :"<<evutil_gai_strerror(errcode)<<endl;
}
else
{
struct evutil_addrinfo *ai;
if (addr->ai_canonname)
{
cout<<"cannoname :"<<addr->ai_canonname<<endl;
}

//addr是一个链表,遍历链表
for( ai = addr ; ai != NULL ; ai = ai->ai_next)
{
char buf[128];
const char *s = NULL;
if ( ai->ai_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
s = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 128);
}
else if ( ai->ai_family == AF_INET6)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128);
}
if(s)
{
cout<<" ->"<<s<<endl;
}
}
evutil_freeaddrinfo(addr);
}
}

int main()
{
struct event_base *base = event_base_new();
struct evdns_base *dnsbase = evdns_base_new(base, 1);
struct evutil_addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC ; //不指定.
hints.ai_flags = EVUTIL_AI_CANONNAME; //返回规范名.
hints.ai_socktype = SOCK_STREAM; //只需要SOCK_STREAM套接字类型
hints.ai_protocol = IPPROTO_TCP; //只需要TCP协议的.
const char* nodename = "github.com";
struct evdns_getaddrinfo_request *req;
req = evdns_getaddrinfo(dnsbase , nodename , NULL , &hints , callback , NULL);

event_base_dispatch(base);
if ( req != NULL)
{
free( req );
}

evdns_base_free(dnsbase, 0);
event_base_free(base);

return 0;
}

Libevent HTTP服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>

#include <event2/event.h>
#include <event2/http.h>
#include <event2/buffer.h>

using namespace std;

void callback(struct evhttp_request *request, void *arg)
{
const struct evhttp_uri * uri = evhttp_request_get_evhttp_uri(request);
char url[8192] = {0};
evhttp_uri_join(const_cast<struct evhttp_uri*>(uri), url, 8192);
cout<<"accept request url:"<<url<<endl;
struct evbuffer *evbuf = evbuffer_new();
if(NULL == evbuf)
{
cout<<"error! evbuffer_new"<<endl;
return;
}
evbuffer_add_printf(evbuf, "%s", "hello libevent http");
evhttp_send_reply(request, HTTP_OK, "OK", evbuf);
evbuffer_free(evbuf);

}

int main()
{
struct event_base *base = event_base_new();
struct evhttp *http = evhttp_new(base);
evhttp_bind_socket(http, "0.0.0.0", 9999);
evhttp_set_gencb(http, callback, NULL);

event_base_dispatch(base);

event_base_free(base);
return 0;
}

参考文献

  1. libevent源码分析
  2. libevent专栏
  3. libevent evhttp学习——http服务端