请注意这是 libev 而不是 libevent 的文章!
这篇文章主要是使用具体的例子,说明如何使用 libev。网上不少文章都是照抄示例,一点用都没有……本文将示例的代码精简一下,补上说明;大家都懂的部分就不赘述了。需要完整源码请查看参考资料。
本文地址:https://segmentfault.com/a/1190000006691243
Reference
Create tcp echo server using libev
基本流程
- 创建 socket,绑定 socket 地址
-
Listen
socket - 创建一个 watcher,用来承载
accept
事件 - 写一个 callback 用来做实际的
accept
调用 - 创建并初始化一个 watcher 用来从 client 中读取请求
- 写一个 callback 用来
read
- 启动 event loop
创建 socket 并绑定 address
注意:原文例子中未显示的是,应当将 fd 设置为非阻塞的。带非阻塞设置的代码如下:
some_init_func()
{
...
sd = socket (PF_INET, SOCK_STREAM, 0);
flags = fcntl (sd, F_GETEL, 0);
fcntl (sd, F_SETEL, flags | O_NONBLOCK);
bzero (&addr, sizeof(addr));
... // 设置 Address 和 port
bind (sd, (struct sockaddr *)(&addr), sizeof(addr));
...
}
监听端口
some_init_func()
{
...
listen (sd, 2);
...
}
准备用来accept()
的 watcher
some_init_func()
{
...
ev_io_init (&w_accept, accept_cb, sd, EV_READ);
ev_io_start (loop, &w_accept);
...
}
回调函数如下:
static void accept_cb (struct ev_loop *loop,
struct ev_io *watcher,
int revents)
{
...
client_sd = accept (watcher->fd, // accept() 调用,接受传入连接
(struct sockaddr *)(&client_addr),
&client_len);
...
w_client = (struct ev_io *)malloc(sizeof(struct ev_io)); // 为 read watcher 准备内存
...
ev_io_init (w_client, read_cb, client_sd, EV_READ); // 这里就只示例 read 事件了。write 事件同理
ev_io_start (loop, w_client);
}
准备用来read()
的 callback
static void read_cb (struct ev_loop *loop,
struct ev_io *watcher,
int revents)
{
...
readCount = recv (watcher->fd, buffer, BUFFER_SIZE, 0); // 读取的方法就视乎程序员的实现啦
send (watcher->fd, buffer, readCount, 0); // 把数据 echo 回去
...
}
原文例子使用的就是recv
/send
,实际上我个人偏爱的是read
/write
启动 event loop
ev_loop (loop, 0); // 这里可以直接使用 default loop
系列篇
Libev 官方文档学习笔记(1)——概述和 ev_loop
Libev 官方文档学习笔记(2)——watcher 基础
Libev 官方文档学习笔记(3)——常用 watcher 接口
使用 libev 构建 TCP 响应服务器的简单流程(本文)