當前位置:
首頁 > 知識 > Nginx的master和worker進程間的通信

Nginx的master和worker進程間的通信

前面單獨分析了master進程和worker的工作情況,本文就大概看一下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該做什麼,所以是一個單向的通道。

master進程每次發送給worker進程的指令用如下一個結構來完成封裝:

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的實現就這麼簡單,沒有什麼多餘的事情。

技術交流Q群:

聊聊技術+妹紙。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 PHP技術大全 的精彩文章:

Nginx 架構初探
zendAPI:讓 PHP 的擴展開發成為一種享受
php的垃圾回收機制——引用計數
colly-go語言編寫的CPU單核超過1k次請求的web採集利器
MultiHttp:高性能的 PHP 封裝的 HTTP Restful 多線程並發請求庫

TAG:PHP技術大全 |