首頁 後端開發 php教程 nginx 進程間通訊-socketpair

nginx 進程間通訊-socketpair

Jul 29, 2016 am 08:58 AM
channel pid socket

    在nginx中,master進程與worker進程之間使用了全雙工通訊方式--socketpair。 socketpair 函數成功執行後會建立一對已經建立連線的socket對,兩個相互通訊的進程分別使用其中一個socket進行讀寫操作,就能夠實現兩個進程間的通訊。

    查看nginx原始碼,可以看到,下面的函數創建了socketpair

ngx_pid_t
ngx_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 <sys/types.h>
#include <sys/socket.h>

#include <stdlib.h>
#include <stdio.h>

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教程有興趣的朋友有所幫助。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
PHP+Socket系列之IO多路復用及實作web伺服器 PHP+Socket系列之IO多路復用及實作web伺服器 Feb 02, 2023 pm 01:43 PM

這篇文章為大家帶來了關於php+socket的相關知識,其中主要介紹了IO多路復用,以及php+socket如何實作web伺服器?有興趣的朋友下面一起來看一下,希望對大家有幫助。

怎麼使用Spring Boot+Vue實現Socket通知推播 怎麼使用Spring Boot+Vue實現Socket通知推播 May 27, 2023 am 08:47 AM

SpringBoot端第一步,引入依賴首先我們需要引入WebSocket所需的依賴,以及處理輸出格式的依賴com.alibabafastjson1.2.73org.springframework.bootspring-boot-starter-websocket第二步,創建WebSocket配置類importorg. springframework.context.annotation.Bean;importorg.springframework.context.annotation.Config

Python的socket與socketserver怎麼使用 Python的socket與socketserver怎麼使用 May 28, 2023 pm 08:10 PM

一、基於TCP協定的socket套接字程式設計1、套接字工作流程先從伺服器端說起。伺服器端先初始化Socket,然後與連接埠綁定(bind),對連接埠進行監聽(listen),呼叫accept阻塞,等待客戶端連線。在這時如果有個客戶端初始化一個Socket,然後連接伺服器(connect),如果連線成功,這時客戶端與伺服器端的連線就建立了。客戶端發送資料請求,伺服器端接收請求並處理請求,然後把回應資料傳送給客戶端,客戶端讀取數據,最後關閉連接,一次互動結束,使用以下Python程式碼實作:importso

php socket無法連線怎麼辦 php socket無法連線怎麼辦 Nov 09, 2022 am 10:34 AM

php socket無法連線的解決方法:1、檢查php是否開啟socket擴充;2、開啟php.ini文件,檢查「php_sockets.dll」是否已載入;3、取消「php_sockets.dll」的註解狀態即可。

PHP實作Socket通訊的方法與技巧 PHP實作Socket通訊的方法與技巧 Mar 07, 2024 pm 02:06 PM

PHP是一種常用的開發語言,可以用來開發各種網頁應用程式。除了常見的HTTP請求和回應以外,PHP也支援透過Socket進行網路通信,實現更靈活和高效的資料互動。本文將介紹PHP如何實作Socket通訊的方法與技巧,並附上具體的程式碼範例。什麼是Socket通訊Socket是一種在網路中進行通訊的方法,可以在不同的電腦之間傳輸資料。透過S

C#常見的網路通訊與安全性問題及解決方法 C#常見的網路通訊與安全性問題及解決方法 Oct 09, 2023 pm 09:21 PM

C#中常見的網路通訊和安全性問題及解決方法在當今互聯網時代,網路通訊已成為了軟體開發中必不可少的一部分。在C#中,我們通常會遇到一些網路通訊的問題,例如資料傳輸的安全性、網路連線的穩定性等。本文將針對C#中常見的網路通訊和安全性問題進行詳細討論,並提供相應的解決方法和程式碼範例。一、網路通訊問題網路連線中斷:網路通訊過程中,可能會出現網路連線的中斷,這會導致

PHP+Socket系列之實現客戶端與服務端資料傳輸 PHP+Socket系列之實現客戶端與服務端資料傳輸 Feb 02, 2023 am 11:35 AM

這篇文章為大家帶來了關於php+socket的相關知識,其中主要介紹了什麼是socket? php+socket如何實現客戶端與服務端資料傳輸?有興趣的朋友下面一起來看一下,希望對大家有幫助。

Win7任務管理器pid怎麼顯示出來 小編教你怎麼顯示出來 Win7任務管理器pid怎麼顯示出來 小編教你怎麼顯示出來 Jan 11, 2024 pm 07:00 PM

很多朋友可能對於pid標識符還比較陌生,可以在任務管理器裡進行查看。但有些用戶打開工作管理員時找不到PID標識符,其實如果用戶想查看進程PID標識符的話,需透過對「任務管理器」相關設定就可以看到了,下面小編就以win7系統為例查看進程PID識別碼的方法。 PID標誌符是windows作業系統對運行的程式的自動分配的一個獨一無二的順序編號,進程中止後PID被系統回收,可能會被繼續分配給新運行的程序,當用戶需要查看進程的時候都會通過任務管理器進行查看,那麼要如何查看進程PID識別碼呢?下面就跟大家分

See all articles