请注意这是 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 响应服务器的简单流程(本文)