日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

NGINX 进程通信机制

發(fā)布時(shí)間:2024/2/28 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NGINX 进程通信机制 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

nginx的進(jìn)程通信分為三種類(lèi)別:linux?系統(tǒng)與nginx?通信,?master?進(jìn)程與worker進(jìn)程通信,?worker進(jìn)程間通信。

master進(jìn)程管理worker進(jìn)程,本文將追溯nginx?的退出過(guò)程。

?

Linux信號(hào)

linux?系統(tǒng)與nginx是通過(guò)信號(hào)才進(jìn)行通信的,通過(guò)信號(hào)控制nginx重啟、關(guān)閉以及加載配置文件等。

?

信號(hào)發(fā)送流程

?

1.?發(fā)送信號(hào)

??? ./nginx –s quit? 向master進(jìn)程發(fā)送信號(hào)

?? 這里有一點(diǎn)是:執(zhí)行 ./nginx –s quit 實(shí)際上是新開(kāi)了一個(gè)master進(jìn)程,只不過(guò)它半路夭折了,即向原master發(fā)送信號(hào)后,

?? 它就死掉啦。它存在的意義就是向原master發(fā)送信號(hào)。

2.?獲取參數(shù)

??? nginx?通過(guò) -s?知道用戶(hù)要給nginx?發(fā)送信號(hào),會(huì)有相應(yīng)的動(dòng)作。?

[cpp]?view plain?copy ?print?
  • ngx_get_options???
  • case?'s':??
  • if?(*p)?{??
  • ????ngx_signal?=?(char?*)?p;??
  • ??
  • }???
  • ??
  • if?(ngx_strcmp(ngx_signal,?"stop")?==?0??
  • ????||?ngx_strcmp(ngx_signal,?"quit")?==?0??
  • ????||?ngx_strcmp(ngx_signal,?"reopen")?==?0??
  • ????||?ngx_strcmp(ngx_signal,?"reload")?==?0)??
  • {??
  • ????ngx_process?=?NGX_PROCESS_SIGNALLER;??
  • ????goto?next;??
  • }??

  • 3.?獲取pid

    ?

    ????要發(fā)送信號(hào),需要知道m(xù)aster進(jìn)程的pid,那如何獲得呢?nginx?啟動(dòng)的時(shí)候?qū)⑵鋵?xiě)入了本地文件中。

    [cpp]?view plain?copy ?print?
  • ngx_int_t??
  • ngx_signal_process(ngx_cycle_t?*cycle,?char?*sig)??
  • {??
  • ????ccf?=?(ngx_core_conf_t?*)?ngx_get_conf(cycle->conf_ctx,?ngx_core_module);??
  • ??
  • ????file.name?=?ccf->pid;??
  • ????file.fd?=?ngx_open_file(file.name.data,?NGX_FILE_RDONLY,??
  • ????????????????????????????NGX_FILE_OPEN,?NGX_FILE_DEFAULT_ACCESS);??
  • ??
  • ????n?=?ngx_read_file(&file,?buf,?NGX_INT64_LEN?+?2,?0);??
  • ????pid?=?ngx_atoi(buf,?++n);??
  • ??
  • ????return?ngx_os_signal_process(cycle,?sig,?pid);??
  • }??
  • ?

    file.name即為配置文件中指定pid所在的文件,該文件存放master的pid。通過(guò)配置文件中的pid字段,指明存放進(jìn)程id文件的地址。


    4.?發(fā)送信號(hào)??

    [cpp]?view plain?copy ?print?
  • ?ngx_int_t??
  • ngx_os_signal_process(ngx_cycle_t?*cycle,?char?*name,?ngx_int_t?pid)??
  • {??
  • ??????ngx_signal_t??*sig;??
  • ??
  • ??????for?(sig?=?signals;?sig->signo?!=?0;?sig++)?{??
  • ??????????if?(ngx_strcmp(name,?sig->name)?==?0)?{??
  • ??????????????if?(kill(pid,?sig->signo)?!=?-1)?{??
  • ??????????????????return?0;??
  • ??????????????}??
  • ??????????}??
  • ??????}??
  • ??
  • ??????return?1;??
  • }??
  • 根據(jù)name到ngx_signal_t的名字中去匹配,找到信號(hào),然后通過(guò)kill向master發(fā)送消息。

    信號(hào)注冊(cè)流程

    ?

    1. 信號(hào)定義

    [cpp]?view plain?copy ?print?
  • typedef?struct?{??
  • int?????signo;??
  • ????????char???*signame;??
  • ????????char???*name;??
  • ????????void??(*handler)(int?signo);??
  • }?ngx_signal_t;??
  • ?

    簡(jiǎn)單解釋一下,signo為信號(hào)的數(shù)字表示,而signame為信號(hào)的名字,name為nginx定義的信號(hào)名,handler為回調(diào)函數(shù)。比如:

    ?

    [cpp]?view plain?copy ?print?
  • {?ngx_signal_value(NGX_SHUTDOWN_SIGNAL),??
  • ??"SIG"?ngx_value(NGX_SHUTDOWN_SIGNAL),??
  • ??"quit",??
  • ???ngx_signal_handler?}??

  • 轉(zhuǎn)換后為:{ SIGQUIT, ?"SIGQUIT",?"quit", ?ngx_signal_handler }, 具體語(yǔ)法規(guī)則見(jiàn)附錄。然后SIGQUIT會(huì)借助于預(yù)處理器進(jìn)行數(shù)字的對(duì)應(yīng),

    SIGQUIT為在signal.h中的宏定義。

    ?

    2. 信號(hào)注冊(cè)

    [cpp]?view plain?copy ?print?
  • ngx_int_t??
  • ngx_init_signals(ngx_log_t?*log)??
  • {??
  • ????ngx_signal_t??????*sig;??
  • ????struct?sigaction???sa;??
  • ??
  • ????for?(sig?=?signals;?sig->signo?!=?0;?sig++)?{??
  • ????????ngx_memzero(&sa,?sizeof(struct?sigaction));??
  • ????????sa.sa_handler?=?sig->handler;??
  • ????????sigemptyset(&sa.sa_mask);??
  • ????????if?(sigaction(sig->signo,?&sa,?NULL)?==?-1)?{??
  • ????????????return?NGX_ERROR;??
  • ????????}??
  • ????}??
  • ????return?NGX_OK;??
  • }??
  • signals?為ngx_signal_t?數(shù)組,內(nèi)部存放所有nginx會(huì)處理的信號(hào)。上述中,通過(guò)sigaction注冊(cè)信號(hào)。

    ?

    3. 信號(hào)處理

    [cpp]?view plain?copy ?print?
  • void??
  • ngx_signal_handler(int?signo)??
  • {??
  • ????switch?(ngx_process)???
  • ????case?NGX_PROCESS_MASTER:??
  • ????????switch?(signo)???
  • ????????case?ngx_signal_value(NGX_SHUTDOWN_SIGNAL):??
  • ????????????ngx_quit?=?1;??
  • }??
  • 設(shè)置全局變量ngx_quit 標(biāo)志為1.

    ?

    4. 響應(yīng)信號(hào)

    [cpp]?view plain?copy ?print?
  • void??
  • ngx_master_process_cycle(ngx_cycle_t?*cycle)??
  • {??
  • ????sigemptyset(&set);??
  • ????sigaddset(&set,?ngx_signal_value(NGX_SHUTDOWN_SIGNAL));??
  • ??
  • ????sigemptyset(&set);????
  • ??
  • ????for?(?;;?)?{??
  • ????????sigsuspend(&set);??
  • ?????
  • ????????if?(ngx_quit)?{??
  • ????????????ngx_signal_worker_processes(cycle,??
  • ????????????????????????????????????????ngx_signal_value(NGX_SHUTDOWN_SIGNAL));??
  • ????????????continue;??
  • ????????}???
  • ????}??
  • }??
  • sigsuspend將阻塞進(jìn)程,直到set中的信號(hào)到達(dá)為止。當(dāng)有信號(hào)達(dá)到,調(diào)用handler函數(shù),然后ngx_quit被設(shè)置為1,

    此時(shí),通過(guò)ngx_signal_worker_processes 向工作進(jìn)程傳遞信號(hào)。

    Socket通信

    master進(jìn)程與worker進(jìn)程通過(guò)sockpair進(jìn)行通信。在nginx中,將這種通信定義為頻道,channel。

    master就是通過(guò)頻道與worker進(jìn)程通信滴。

    ?

    1. 頻道定義

    [cpp]?view plain?copy ?print?
  • typedef?struct?{??
  • ?????ngx_uint_t??command;??
  • ?????ngx_pid_t???pid;??
  • ?????ngx_int_t???slot;??
  • ?????ngx_fd_t????fd;??
  • }?ngx_channel_t;??
  • ?

    2. 注冊(cè)頻道

    ?

    其一:創(chuàng)建頻道,其實(shí)就是socketpair,在啟動(dòng)worker進(jìn)程的時(shí)候創(chuàng)建頻道

    [cpp]?view plain?copy ?print?
  • ngx_pid_t??
  • ngx_spawn_process(ngx_cycle_t?*cycle,?ngx_spawn_proc_pt?proc,?void?*data,??
  • ????char?*name,?ngx_int_t?respawn)??
  • {??
  • ????socketpair(AF_UNIX,?SOCK_STREAM,?0,?ngx_processes[s].channel)?==?-1);??
  • ????ngx_nonblocking(ngx_processes[s].channel[0])?==?-1);??
  • ????ngx_nonblocking(ngx_processes[s].channel[1])?==?-1);??
  • ?????????????
  • ????ngx_channel?=?ngx_processes[s].channel[1];??
  • }??
  • 在linux下,使用socketpair函數(shù)能夠創(chuàng)建一對(duì)套節(jié)字進(jìn)行進(jìn)程間通信(IPC)。

    函數(shù)原形:
    #include <sys/types.h>
    #include <sys/socket.h>

    int socketpair(int domain, int type, int protocol, int sv[2]);

    參數(shù)1(domain):表示協(xié)議族,在Linux下只能為AF_LOCAL或者AF_UNIX。(自從Linux 2.6.27后也支持SOCK_NONBLOCK和SOCK_CLOEXEC)
    參數(shù)2(type):表示協(xié)議,可以是SOCK_STREAM或者SOCK_DGRAM。SOCK_STREAM是基于TCP的,而SOCK_DGRAM是基于UDP的
    參數(shù)3(protocol):表示類(lèi)型,只能為0
    參數(shù)4(sv[2]):套節(jié)字柄對(duì),該兩個(gè)句柄作用相同,均能進(jìn)行讀寫(xiě)雙向操作
    返回結(jié)果: 0為創(chuàng)建成功,-1為創(chuàng)建失敗,并且errno來(lái)表明特定的錯(cuò)誤號(hào),具體錯(cuò)誤號(hào)如下所述:

    ? ?EAFNOSUPPORT:本機(jī)上不支持指定的address。

    ? ?EFAULT: 地址sv無(wú)法指向有效的進(jìn)程地址空間內(nèi)。

    ? ?EMFILE: 已經(jīng)達(dá)到了系統(tǒng)限制文件描述符,或者該進(jìn)程使用過(guò)量的描述符。

    ? ?EOPNOTSUPP:指定的協(xié)議不支持創(chuàng)建套接字對(duì)。

    ? ?EPROTONOSUPPORT:本機(jī)不支持指定的協(xié)議。

    注意:

    1、該函數(shù)只能用于UNIX域(LINUX)下。
    2、只能用于有親緣關(guān)系的進(jìn)程(或線(xiàn)程)間通信。
    3、所創(chuàng)建的套節(jié)字對(duì)作用是一樣的,均能夠可讀可寫(xiě)(而管道PIPE只能進(jìn)行單向讀或?qū)?#xff09;。
    4、在讀的時(shí)候,管道內(nèi)必須有內(nèi)容,否則將會(huì)阻塞;簡(jiǎn)而言之,該函數(shù)是阻塞的。
    ?

    設(shè)置非阻塞,同時(shí),將ngx_channel賦值。
    其二:加入epoll等待數(shù)據(jù)到來(lái),在worker進(jìn)程初始化的時(shí)候加入

    [cpp]?view plain?copy ?print?
  • static?void??
  • ngx_worker_process_init(ngx_cycle_t?*cycle,?ngx_uint_t?priority)??
  • {??
  • ????if?(ngx_add_channel_event(cycle,?ngx_channel,?NGX_READ_EVENT,??
  • ??????????????????????????????ngx_channel_handler)??
  • ????????==?NGX_ERROR)??
  • ????{??
  • ????????exit(2);??
  • ????}??
  • }??
  • ngx_channel_handler為回調(diào)函數(shù)。

    ?

    3. 發(fā)送消息

    [cpp]?view plain?copy ?print?
  • static?void??
  • ngx_signal_worker_processes(ngx_cycle_t?*cycle,?int?signo)??
  • {??
  • ????ngx_channel_t??ch;??
  • ??
  • ????switch?(signo)?{??
  • ????case?ngx_signal_value(NGX_SHUTDOWN_SIGNAL):??
  • ????????ch.command?=?NGX_CMD_QUIT;??
  • ????????break;??
  • ????}??
  • ??
  • ????for?(i?=?0;?i?<?ngx_last_process;?i++)??
  • ????????????ngx_write_channel(ngx_processes[i].channel[0],??
  • ??????????????????????????????????&ch,?sizeof(ngx_channel_t),?cycle->log)??
  • ???????
  • }??
  • master進(jìn)程通過(guò)ngx_signal_woker_processes向worker進(jìn)程發(fā)送消息。

    ?

    ?

    ?

    4. 響應(yīng)消息

    [cpp]?view plain?copy ?print?
  • static?void??
  • ngx_channel_handler(ngx_event_t?*ev)??
  • {??
  • ????c?=?ev->data;??
  • ????for?(?;;?)?{??
  • ??
  • ????????n?=?ngx_read_channel(c->fd,?&ch,?sizeof(ngx_channel_t),?ev->log);??
  • ????????switch?(ch.command)?{??
  • ????????case?NGX_CMD_QUIT:??
  • ????????????ngx_quit?=?1;??
  • ????????????break;??
  • ????????}??
  • ????}??
  • }??
  • worker進(jìn)程通過(guò)ngx_read_channel讀取消息,然后根據(jù)command判斷是什么消息,同時(shí)設(shè)置worker進(jìn)程的ngx_quit變量。

    ?

    5. woker進(jìn)程受理

    ?

    [cpp]?view plain?copy ?print?
  • static?void??
  • ngx_worker_process_cycle(ngx_cycle_t?*cycle,?void?*data)??
  • {??
  • ????ngx_uint_t?????????i;??
  • ????ngx_connection_t??*c;??
  • ??
  • ????for?(?;;?)?{??
  • ????????ngx_process_events_and_timers(cycle);??
  • ????????if?(ngx_quit)?{??
  • ????????????ngx_quit?=?0;??
  • ??
  • ????????????if?(!ngx_exiting)?{??
  • ????????????????ngx_close_listening_sockets(cycle);??
  • ????????????????ngx_exiting?=?1;??
  • ????????????}??
  • ????????}??
  • ?

    worker內(nèi)部ngx_worker_process_cycle為一個(gè)循環(huán),處理事件,當(dāng)檢測(cè)到退出標(biāo)志后,做相應(yīng)處理

    ?

    共享內(nèi)存

    ?

    worker進(jìn)程間則是通過(guò)比較快速的共享內(nèi)存進(jìn)行通信。

    ?

    1. mmap 匿名

    ? 即不與文件關(guān)聯(lián),不需要?jiǎng)?chuàng)建文件刪除文件,簡(jiǎn)單高效。但有可能有些系統(tǒng)不支持,所以若不支持,采用第二種方案。

    ?

    2.mmap /dev/zero

    ? 與字符設(shè)備/dev/zero關(guān)聯(lián),相當(dāng)于打開(kāi)一個(gè)文件,但mac os不支持,所以采用第三種方式。

    ? fd = open(“/dev/zero”, O_RDWR);

    ? mmap(NULL, sizeof(int), PROT_READ |PROT_WRITE, MAP_SHARED, fd, 0).

    ?

    3.shmget 古老的system v獲取

    ? 繁瑣,但所有系統(tǒng)都支持

    ?

    由master進(jìn)程創(chuàng)建共享變量,worker進(jìn)程共享。nginx?解決驚群?jiǎn)栴},是通過(guò)設(shè)置互斥鎖,

    只有擁有互斥鎖的工作進(jìn)程才能擔(dān)負(fù)與客戶(hù)建立連接的任務(wù),這個(gè)互斥鎖就放于共享內(nèi)存中。

    另外,ngin統(tǒng)計(jì)連接數(shù),這個(gè)全局變量也放于共享內(nèi)存中,多個(gè)工作進(jìn)程可以去改寫(xiě)這個(gè)變量,

    當(dāng)然,需要一些互斥機(jī)制。

    ?

    共享內(nèi)存一個(gè)小例子:

    ?

    [cpp]?view plain?copy ?print?
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<sys/mman.h>??
  • #include?<unistd.h>??
  • #include?<fcntl.h>??
  • ??
  • int??
  • main(int?argc,?char?*argv[])??
  • {??
  • ????int?*num;??
  • ????pid_t?pid;??
  • ??
  • ??????
  • ????num?=?(int*)?mmap(NULL,?sizeof(int),?PROT_READ?|?PROT_WRITE,??
  • ??????????????????????MAP_SHARED?|?MAP_ANONYMOUS,?0,?0);??
  • ??????
  • ????if?((pid?=?fork())?<?0)?{??
  • ????????perror("fork?error");??
  • ????????exit(0);??
  • ????}?else?if?(pid?==?0)?{??
  • ????????*num?+=?5;??
  • ????????exit(0);??
  • ????}??
  • ??????
  • ????waitpid(pid,?NULL,?0);??
  • ????printf("father?get?data:?%d\n",?*num);??
  • ???????
  • ????return?0;??
  • }??
  • ?

    ?

    ?

    附錄

    ?

    1. #轉(zhuǎn)換為字符

    ? 在define宏定義中,#代表將參數(shù)轉(zhuǎn)換成字符串, 即“ ”.

    ? #definevalue(n)? #n

    ?char *str = value(12345);? è str = “12345”

    ?

    2. ##連接成一個(gè)token

    ? 在define宏定義中,兩個(gè)##表示將參數(shù)連接起來(lái)構(gòu)成一個(gè)標(biāo)示符

    ?#define value(n)?? val##n

    ? intval1 = 3;

    ?printf(“%d\n”, value(1));?? è val1

    ?

    3. 字符串連接

    ?? //C語(yǔ)言中,“ ”表示空串?? 不準(zhǔn)確

    ??char *str = “123”?? “456”;

    ?? 等效

    ??char *str = “123456”;

    ?? 解析: 相當(dāng)123”?? “456”?紅色是一對(duì),空串省略

    ?

    4.?為什么worker?與master采用socketpair進(jìn)行通信

    ???? worker進(jìn)程有一個(gè)循環(huán),在不停的處理請(qǐng)求,怎樣接收master發(fā)送的數(shù)據(jù)呢。而socketpair為一種套接字,將它加入epoll中,通過(guò)事件模塊獲取該套接字,進(jìn)行處理。ngx_write_channel將數(shù)據(jù)寫(xiě)入channel。而在ngx_process_cycle.c->ngx_worker_process_init初始化的時(shí)候,已經(jīng)調(diào)用ngx_add_channel_event將套接字寫(xiě)入epoll中,后續(xù)向套接字寫(xiě)數(shù)據(jù),epoll能檢測(cè)到,并調(diào)用注冊(cè)的回調(diào)函數(shù)ngx_channel_handler,將相應(yīng)標(biāo)志位設(shè)1(ngx_quit)。

    總結(jié)

    以上是生活随笔為你收集整理的NGINX 进程通信机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。