使用 libev 構建 TCP 響應伺服器(echo server)的簡單流程
阿新 • • 發佈:2019-01-10
請注意這是 libev 而不是 libevent 的文章!
這篇文章主要是使用具體的例子,說明如何使用 libev。網上不少文章都是照抄示例,一點用都沒有……本文將示例的程式碼精簡一下,補上說明;大家都懂的部分就不贅述了。需要完整原始碼請檢視參考資料。
Reference
基本流程
-
建立 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