> 백엔드 개발 > PHP 튜토리얼 > nginx 프로세스 간 통신 소켓 쌍

nginx 프로세스 간 통신 소켓 쌍

WBOY
풀어 주다: 2016-07-29 08:58:14
원래의
1478명이 탐색했습니다.

nginx에서는 마스터 프로세스와 작업자 프로세스 간에 전이중 통신 방식인 소켓페어를 사용합니다. 소켓 쌍 기능이 성공적으로 실행되면 연결이 설정된 소켓 쌍이 생성됩니다. 서로 통신하는 두 프로세스는 소켓 중 하나를 사용하여 각각 읽기 및 쓰기 작업을 수행할 수 있으므로 두 프로세스 간의 통신이 가능해집니다.

nginx 소스 코드를 보면 다음 함수가 소켓 쌍을 생성하는 것을 볼 수 있습니다

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->exec 함수 계열을 사용하는 경우 리소스 누출을 방지하기 위해 원래 설명자가 정상적으로 닫히도록 하는 더 나은 방법을 사용할 수 있습니다. 즉, 위 코드에서는 소켓에 fcntl(FD_CLOEXEC) 함수가 호출되고 소켓의 속성이 설정됩니다. exec 함수 계열이 호출되면 소켓이 자동으로 닫힙니다. 소켓이 생성된 직후에 FD_CLOEXEC 속성을 설정하는 이 방법을 사용하면 exec 생성 프로세스 전에 관련 소켓을 수동으로 닫을 필요가 없으며 특히 많은 수의 설명자가 생성되고 관리되는 경우 매우 실용적입니다.

다음과 같은 방법을 사용하여 작업하는 경우가 많습니다.

#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;
}
로그인 후 복사

포크 이전에는 현재 프로세스에서 소켓 쌍, 즉 소켓 쌍을 생성한 것을 볼 수 있습니다. 이 소켓 쌍의 경우 하나는 서버측 fds[0]으로 간주되고 다른 하나는 클라이언트측 fds[1]로 간주될 수 있습니다. fds[0]과 fds[1] 사이에 설정된 링크를 통해 완료할 수 있습니다. 전이중 통신.

Fork가 실행된 후 하위 프로세스가 생성됩니다. 자식 프로세스에서는 부모 프로세스에 의해 생성된 소켓 쌍이 자연스럽게 fds'로 복사되어 자식 프로세스에 존재하게 됩니다. 상위 프로세스가 계속 실행됩니다. 이때 상위 프로세스와 하위 프로세스에는 동일한 소켓 쌍이 존재하게 됩니다.

메인 프로세스의 fds[0]에 데이터를 쓰고, 자식 프로세스의 fds'[1]에서 데이터를 읽어 부모 프로세스와 자식 간의 관계를 구현한다고 상상해보세요. . 프로세스 간 통신. 물론, 메인 프로세스 fds[1]에 데이터가 기록되면, 기록된 데이터는 하위 프로세스 fds'[0]에서도 읽혀집니다. 실제 사용에서는 통신을 위해 한 쌍의 소켓만 예약하면 되며 나머지 두 소켓은 각각 상위 프로세스와 하위 프로세스에서 닫힐 수 있습니다.

물론 fds의 소켓을 어떤 방식으로든 다른 프로세스에 전달할 수 있다면 소켓쌍 프로세스 간 통신도 달성할 수 있습니다.


위 내용은 관련 내용을 포함하여 nginx 프로세스 간 통신 소켓 쌍을 소개한 내용이 PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿