Nginx源码学习——master进程与worker进程之间的s

2018-10-17  本文已影响0人  丹丘生___

master进程与worker进程是通过socket进行通信的。socket描述符保存在结构体ngx_process_t的channel数组成员中。

//进程相关信息
typedef struct {
    ngx_pid_t           pid;//进程ID
    int                 status;//由waitpid系统调用获取到的进程状态

    //这是由socketpair系统调用产生出的用于进程间通信的socket句柄,这一对socket句柄可以
    //互相通信,目前用于master父进程与worker子进程间的通信。
    ngx_socket_t        channel[2];
    //子进程的循环执行方法,当父进程调用ngx_spawn_process生成子进程时使用
    ngx_spawn_proc_pt   proc;
    void               *data;

    //进程名称,操作系统中显示的进程名称与name相同
    char               *name;

    //标志位,为1时表示在重新生成子进程
    unsigned            respawn:1;
    //标志位,为1时表示正在生成子进程
    unsigned            just_spawn:1;
    //标志位,为1时表示在进行父、子进程分离
    unsigned            detached:1;
    //标志位,为1时表示进程正在退出
    unsigned            exiting:1;
    //标志位,为1时表示进程已经退出
    unsigned            exited:1;
} ngx_process_t;

channel数组保存了两个socket描述符,这一对socket可以互相通信,实现了TCP的全双工。

socket的创建

socket是由socketpair系统调用创建的,下面是ngx_spawn_process函数中的代码片段.
由代码可以看到,创建一对socket后,还有一系列后续操作:

        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;
        }

        ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                       "channel %d:%d",
                       ngx_processes[s].channel[0],
                       ngx_processes[s].channel[1]);

        //使用ioctl函数,将socket设置为非阻塞socket
        if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          ngx_nonblocking_n " failed while spawning \"%s\"",
                          name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
        }

        if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          ngx_nonblocking_n " failed while spawning \"%s\"",
                          name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
        }

        /*以下代码调用ioctl和fcntl函数设置为基于SOCKET的异步IO,分为两步(无先后):
         * 1、通知套接字当I/O操作不会阻塞时发信号。
         * 2、建立套接字所有权,这样信号可以被传递到合适的进程。
         * */
        on = 1;
        //通知套接字当I/O操作不会阻塞时发信号
        if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
        }

        //建立套接字所有权,即被那个进程所拥有,这样信号可以传递到该进程。
        //ngx_pid指当前进程ID,设置该进程if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
        }

        //当进程调用exec运行的时候,关闭该socket描述符
        if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
                           name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
        }

        if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
                           name);
            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;
    }
上一篇 下一篇

猜你喜欢

热点阅读