libevent简单使用

最近想要自己写一个简单的http server,因为之前的那个是epoll的,只能运行在linux平台上。
于是我便找到了平台通用的libevent

libevent是事件驱动的,支持异步的网络框架。

十分值得学习。

由于基于reactor模型,所以事件抽象为eventevent loopreactorevent handler是各种回调函数。

struct event
要创建event一般使用event_new函数。

1
2
struct event *event_new(struct event_base *base, evutil_socket_t fd,
short what, event_callback_fn cb, void *arg);

base参数是我们要把这个事件绑定的event loop
fd就是socket fd,只不过为了统一windows,重新定义了一下
what是触发事件,
选项是下面的或

1
2
3
4
5
6
#define EV_TIMEOUT      0x01
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10
#define EV_ET 0x20

cb就是触发事件的回调函数,
arg是我们自定义传进去的参数。

而回调函数的格式是一样的。 比如。

1
void on_write(int conn_fd, short event, void *arg)

第一个conn_fd就是我们event_new 中的fd, 第二个便是what,第三个是arg

struct event_base
创建event_base使用。

1
struct event_base* event_base_new()

把一个event注册到event_base

1
2
3
4
struct event *base = event_base_new();
struct event* ev_listen = event_new(base, listen_fd, EV_READ | EV_PERSIST, on_accept, NULL);
event_base_set(base, ev_listen);
event_add(ev_listen, NULL);

开始执行loop

1
int event_base_dispatch(struct event_base *base);

还有类似free函数

1
2
event_base_free(struct event base*);
event_free(struct event*);

一个简答的example
打开一个socket,每有一次连接进来便接受并关闭。

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
int socket_bind_listen(char *addr, char *port) {
int listen_fd;
unsigned short Port;
struct sockaddr_in addr_s;
//AF_INET ipv4
//SOCK_STREAM 以流的方式传递
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) {
log_err("%s", strerror(errno));
exit(1);
}
//get port
Port = (unsigned short) atoi(port);

memset(&addr_s, 0, sizeof(addr_s));
addr_s.sin_family = AF_INET;
addr_s.sin_addr.s_addr = inet_addr(addr);
addr_s.sin_port = htons(Port);

int ret = bind(listen_fd, (struct sockaddr *) &addr_s, sizeof(addr_s));
if (ret == -1) {
perror("bind:");
close(listen_fd);
exit(1);
}
if (listen(listen_fd, BACKLOG) == -1) {
perror("listen:")
close(listen_fd);
exit(1);
}
return listen_fd;
}

void on_accept(int listen_fd, short events, void *arg) {
int conn_fd = accept(listen_fd, NULL, 0);

if (conn_fd < 0) {
return;
}
printf("get connect\n");
close(conn_fd);
}

int main(int argc, char *argv[])
{
int listen_fd = socket_bind_listen("127.0.0.1", "8080");
struct event_base *base = event_base_new();
struct event* ev_listen = event_new(base, listen_fd, EV_READ | EV_PERSIST, on_accept, NULL);
event_base_set(base, ev_listen);
event_add(ev_listen, NULL);
event_base_dispatch(base);
event_base_free(base);
event_free(ev_listen);
}