本文就大概看一下master進程和worker進程之間是如何使用 channel來完成通信的。這部分實現的源碼主要分布于src/os/unix/channel.h和channel.c兩個文件中。實現極其簡單,沒 有什么復雜的邏輯。下面,我繪制了一個簡單的master進程和worker進程間的關系,圖中的箭頭符號指出數據是由master進程傳給worker 進程,而沒有從worker到master;這是因為channel不是一個普通的數據傳輸管道,在Nginx中它僅僅是用著master發送指令給 worker的一個管道,master借此channel來告訴worker進程該做什么了,worker卻不需要告訴master該做什么,所以是一個 單向的通道。

typedef struct {
ngx_uint_t command;
ngx_pid_t pid;
ngx_int_t slot;
ngx_fd_t fd;
} ngx_channel_t;
這個結構中的4個字段分別是發送的指令、worker進程的pid、worker進程的slot(在ngx_proecsses中的索引)及一個文 件描述符。master進程可能會將一個打開的文件描述符發送給worker進程進行讀寫操作,那么此時就需要填寫fd這個字段了。worker進程在收 到一個這樣的結構數據后,通過判斷command的值來采取相應的動作;command就是master給worker下達的命令。
master進程用于處理SIGCHLD信號的函數ngx_reap_children中就有向worker進程發送關閉channel的指令,我們看看這個例子是怎么做的。
ch.command = NGX_CMD_CLOSE_CHANNEL;
ch.fd = -1;
ch.pid = ngx_processes[i].pid;
ch.slot = i;
ngx_write_channel(ngx_processes[n].channel[0],
&ch, sizeof(ngx_channel_t), cycle->log);
這幾行代碼是我從ngx_reap_children函數中拼湊起來的,所以看上去好像有點奇怪,不那么順暢;但卻清晰的給我們展現了master 進程怎么給一個worker進程發送指令,此處發送的指令時NGX_CMD_CLOSE_CHANNEL。發送指令的函數 ngx_write_channel是利用sendmsg來完成,《Unix網絡編程》可以詳細了解sendmsg。
worker進程在調用ngx_worker_process_init進行初始化的時候,使用了如下兩行代碼將channel放到epoll等事件處理模塊中。
if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
ngx_channel_handler)
== NGX_ERROR)
{
/* fatal */
exit(2);
}
當master進程發來指令后,就調用ngx_channel_handler函數進行事件的響應。下面濃縮的代碼給出了ngx_channel_handler所做的事情。
/*
讀出master進程發送給過來的指令數據, ngx_read_channel
是利用recvmsg實現,詳細介紹見《unix網絡編程》
*/
n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);
/*
判斷command的值,從而采取具體的動作,代碼意圖都寫得很明顯,
就不在這里多說了。
*/
switch (ch.command) {
case NGX_CMD_QUIT:
ngx_quit = 1;
break;
case NGX_CMD_TERMINATE:
ngx_terminate = 1;
break;
case NGX_CMD_REOPEN:
ngx_reopen = 1;
break;
case NGX_CMD_OPEN_CHANNEL:
ngx_processes[ch.slot].pid = ch.pid;
ngx_processes[ch.slot].channel[0] = ch.fd;
break;
case NGX_CMD_CLOSE_CHANNEL:
if (close(ngx_processes[ch.slot].channel[0]) == -1) {
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
"close() channel failed");
}
ngx_processes[ch.slot].channel[0] = -1;
break;
}
Nginx中關于整個channel的實現就這么簡單,沒有什么多余的事情。