nginx 處理序間通訊-socketpair

來源:互聯網
上載者:User
在nginx中,master進程與worker進程之間使用了一種全雙工系統通訊方式--socketpair。socketpair 函數成功執行後會建立一對已經建立串連的socket對,兩個相互連信的進程分別使用其中一個socket進行讀寫操作,就能夠實現兩進程間的通訊。

查看nginx源碼,可以看到,下面的函數建立了socketpair

ngx_pid_tngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,    char *name, ngx_int_t respawn){    u_long     on;    ngx_pid_t  pid;    ngx_int_t  s;    /. ......省略...... ./    if (respawn != NGX_PROCESS_DETACHED) {        /* Solaris 9 still has no AF_LOCAL */        //建立socketpair        if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)        {            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,                          "socketpair() failed while spawning \"%s\"", name);            return NGX_INVALID_PID;        }        //非阻塞        if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {            ngx_close_channel(ngx_processes[s].channel, cycle->log);            return NGX_INVALID_PID;        }        //非阻塞        if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {            ngx_close_channel(ngx_processes[s].channel, cycle->log);            return NGX_INVALID_PID;        }        //非同步        on = 1;        if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {            ngx_close_channel(ngx_processes[s].channel, cycle->log);            return NGX_INVALID_PID;        }        //設定將要在檔案描述詞fd上接收SIGIO 或 SIGURG事件訊號的進程或進程組標識 。        if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {            ngx_close_channel(ngx_processes[s].channel, cycle->log);            return NGX_INVALID_PID;        }        //設定close_on_exec,當通過exec函數族建立了新進程後,原進程的該socket會被關閉        if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {            ngx_close_channel(ngx_processes[s].channel, cycle->log);            return NGX_INVALID_PID;        }        //設定close_on_exec,當通過exec函數族建立了新進程後,原進程的該socket會被關閉        if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {            ngx_close_channel(ngx_processes[s].channel, cycle->log);            return NGX_INVALID_PID;        }        ngx_channel = ngx_processes[s].channel[1];    } else {        ngx_processes[s].channel[0] = -1;        ngx_processes[s].channel[1] = -1;    }    ngx_process_slot = s;    pid = fork();    switch (pid) {    case -1:        ngx_close_channel(ngx_processes[s].channel, cycle->log);        return NGX_INVALID_PID;    case 0:        //fork成功,子進程建立,同時相關socket描述符也會被複製一份        ngx_pid = ngx_getpid();        proc(cycle, data);        break;    default:        break;    }    /. ......省略...... ./    return pid;}

fork成功後,原進程的descriptor也會被複製一份,如果在fork的進程中該描述符不再使用,需要我們及時關閉。

如果我們使用的是 fork->exec函數族 的形式建立新進程的話,我們可以採用更好的辦法來確保原有的descriptor被正常關閉,避免資源的泄漏。也就是上邊代碼中對socket調用fcntl(FD_CLOEXEC)函數,設定該socket的屬性:當exec函數族被調用後,該socket會被自動關閉。使用這種在socket建立後立即設定FD_CLOEXEC屬性的辦法,避免了我們在exec建立進程前手動關閉相關socket的操作,尤其是當有大量的descriptor被建立、管理的時候非常實用。

很多時候我們是使用下邊的方法進行操作的:

#include #include #include #include int main(){    pid_t  pid;    int    fds[2];    int    valRead, valWrite;    if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, fds))    {        return 0;    }    pid = fork();    if (0 == pid)    {        pid = getpid();        printf("[%d]-child process start", pid);        close(fds[0]);                //read write on fds[1]        write(fds[1], &valWrite, sizeof(valWrite));         read(fds[1], &valRead, sizeof(valRead));    }    else if (0 < pid)    {        pid = getpid();        printf("[%d]-parent process continue", pid);        close(fds[1]);        //read write on fds[0]        read(fds[0], &valRead, sizeof(valRead));        write(fds[0], &valWrite, sizeof(valWrite));     }    else    {        printf("%s", "fork failed");    }    return 0;}

可以看到,fork前,當前進程建立了一對socket,也就是socketpair。對於這對socket,可以看作一個是伺服器端fds[0],另一個是用戶端fds[1],通過fds[0]與fds[1]之間建立的連結,我們可以完成全雙工系統通訊。

fork執行後,建立了子進程。在子進程中,之前父進程建立的socketpair自然也會被複製一份為fds',存在於子進程中。父進程繼續執行。這個時候,在父進程和子進程中會存在相同socketpair。

試想,我們在主進程中向fds[0]中寫入資料,在子進程中的fds'[1]上就會讀取到該資料,這樣就實現了父進程與子進程間的通訊。當然,在主進程fds[1]上寫資料,在子進程fds'[0]上也會讀到寫入的資料。我們實際使用中,只需要保留一對socket用來通訊就可以了,另外兩個socket就可以分別在父進程和子進程中關閉不用了。

當然了,如果我們能夠把fds中的一個socket通過某種方式傳遞給另一個進程,那麼也可以實現socketpair處理序間通訊了。


以上就介紹了nginx 處理序間通訊-socketpair,包括了方面的內容,希望對PHP教程有興趣的朋友有所協助。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.