nginx中相关通信总结

news2024/12/24 9:05:08

目录

1.master进程监听socket

2.master和worker进程通信机制

2.1通信渠道

2.2通信方法

2.3通信内容

2.4子进程事件处理

3.epoll封装

4.linux系统下信号查看


1.master进程监听socket

nginx在master进程socket bind listen,accept在通过epoll在子进程中控制,代码如下:

ngx_int_t
ngx_open_listening_sockets(ngx_cycle_t *cycle)
{
...
    s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0);
...
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                               (const void *) &reuseaddr, sizeof(int))
                    == -1)
...
    if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
...
    if (listen(s, ls[i].backlog) == -1) {
...
    
}

调用堆栈如下:
ngx_open_listening_sockets(ngx_cycle_t * cycle) (nginx-1.22.1/src/core/ngx_connection.c:604)
ngx_init_cycle(ngx_cycle_t * old_cycle) (nginx-1.22.1/src/core/ngx_cycle.c:618)
main(int argc, char * const * argv) (nginx-1.22.1/src/core/nginx.c:292)

2.master和worker进程通信机制

2.1通信渠道

创建套接字组用于读和写,master用fd[0]写,worker用fd[1]进行读
socketpair

2.2通信方法

master用sendmsg发送,work用recvmsg接收
#include <sys/types.h>
#include <sys/socket.h>

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

2.3通信内容

struct msghdr

2.4子进程事件处理

子进程注册fd[1] -> ngx_channel读事件到epoll上

static void
ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
{
    ...
    if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
                              ngx_channel_handler)
        == NGX_ERROR)
    {
        /* fatal */
        exit(2);
    }
}

ngx_channel在如下函数进行赋值,为fd[1]
ngx_pid_t
ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
    char *name, ngx_int_t respawn)
{
    ...
    ngx_channel = ngx_processes[s].channel[1];
    ...
}

3.epoll封装

文件:
nginx-1.22.1/src/event/modules/ngx_epoll_module.c
结构:
static ngx_event_module_t  ngx_epoll_module_ctx = {
    &epoll_name,
    ngx_epoll_create_conf,               /* create configuration */
    ngx_epoll_init_conf,                 /* init configuration */

    {
        ngx_epoll_add_event,             /* add an event */
        ngx_epoll_del_event,             /* delete an event */
        ngx_epoll_add_event,             /* enable an event */
        ngx_epoll_del_event,             /* disable an event */
        ngx_epoll_add_connection,        /* add an connection */
        ngx_epoll_del_connection,        /* delete an connection */
#if (NGX_HAVE_EVENTFD)
        ngx_epoll_notify,                /* trigger a notify */
#else
        NULL,                            /* trigger a notify */
#endif
        ngx_epoll_process_events,        /* process the events */
        ngx_epoll_init,                  /* init the events */
        ngx_epoll_done,                  /* done the events */
    }
};

4.linux系统下信号查看

kill -l

5.信号处理模拟

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <stdint.h>

int parentProcess(int* fds, int num) {
	if (num < 2) {
		return -1;
	}
	close(fds[0]); // 关闭fds[0] 使用fds[1]读写,子进程中关闭fds[1] 使用fds[0]读写
	char buf[128] {0};
	char *pStr = (char*)"hello child, I am parent";
	int inum = 0;
	while (inum++ < 3) {
		memset(buf, 0x00, sizeof(buf));
		//写
		write(fds[1], pStr, strlen(pStr));
		//读
		read(fds[1], buf, 128);
		printf("parent [%d] %d :: %s\n", getpid(), inum, buf);
		sleep(1);
	}

	close(fds[1]);
	return 0;
}

int childProcess(int* fds, int num) {
	if (num < 2) {
		return -1;
	}
	close(fds[1]);
	char buf[128] {0};
	char *pStr = (char*)"hello parent, I am child";
	char sendBuf[128] = {0};
	sprintf(sendBuf, "hello parent, I am child %d", getpid());
	int inum = 0;
	while (inum++ < 3) {
		memset(buf, 0x00, sizeof(buf));
		//读
		read(fds[0], buf, 128);
		printf("child [%d] %d :: %s\n", getpid(), inum, buf);
		//写
		write(fds[0], sendBuf, strlen(sendBuf));
		sleep(1);
	}
	
	close(fds[0]);
	return 0;
}

//设置文件描述符非阻塞
int fd_nonblocking(int s)
{
    int  nb;
    nb = 1;
	//方法一
	/*
	int flag = fcntl(s, F_GETFL);
    flag |= O_NONBLOCK;
    return fcntl(s, F_SETFL, flag);
	*/
	//方法二
    return ioctl(s, FIONBIO, &nb);
}

int close_channel(int* fds) {
	if (close(fds[0]) == -1) {
        printf("close() channel fds[0] failed\n");
    }

    if (close(fds[1]) == -1) {
        printf("close() channel fds[1] failed\n");
    }

	return 0;
}

void testNonblockingSocketFd(int* fds) {
	if (-1 == fd_nonblocking(fds[0])) {
		printf("fd_nonblocking fds[0] failed\n");
		close_channel(fds);
	}
	if (-1 == fd_nonblocking(fds[1])) {
		printf("fd_nonblocking fds[1] failed\n");
		close_channel(fds);
	}
}

struct TDataExchangeChannel {
	int fds[2];
};

#define GROUP_NUM 2

typedef struct {
    int     signo;
    char   *signame;
    char   *name;
    void  (*handler)(int signo, siginfo_t *siginfo, void *ucontext);
} ngx_signal_t;

#define ngx_signal_helper(n)     SIG##n
#define ngx_signal_value(n)      ngx_signal_helper(n)

#define ngx_value_helper(n)   #n
#define ngx_value(n)          ngx_value_helper(n)

#define NGX_SHUTDOWN_SIGNAL      QUIT
#define NGX_TERMINATE_SIGNAL     TERM
#define NGX_NOACCEPT_SIGNAL      WINCH
#define NGX_RECONFIGURE_SIGNAL   HUP

#if (NGX_LINUXTHREADS)
#define NGX_REOPEN_SIGNAL        INFO
#define NGX_CHANGEBIN_SIGNAL     XCPU
#else
#define NGX_REOPEN_SIGNAL        USR1
#define NGX_CHANGEBIN_SIGNAL     USR2
#endif

#define ngx_errno                  errno

typedef intptr_t        ngx_int_t;
typedef int             ngx_err_t;
typedef uintptr_t       ngx_uint_t;

#define NGX_PROCESS_SINGLE     0
#define NGX_PROCESS_MASTER     1
#define NGX_PROCESS_SIGNALLER  2
#define NGX_PROCESS_WORKER     3
#define NGX_PROCESS_HELPER     4

#define  NGX_OK          0
#define  NGX_ERROR      -1
#define  NGX_AGAIN      -2
#define  NGX_BUSY       -3
#define  NGX_DONE       -4
#define  NGX_DECLINED   -5
#define  NGX_ABORT      -6

ngx_uint_t    ngx_process;

void
ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext);

ngx_signal_t  signals[] = {
    { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
      "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
      "reload",
      ngx_signal_handler },

    { ngx_signal_value(NGX_REOPEN_SIGNAL),
      "SIG" ngx_value(NGX_REOPEN_SIGNAL),
      "reopen",
      ngx_signal_handler },

    { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
      "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
      "",
      ngx_signal_handler },

    { ngx_signal_value(NGX_TERMINATE_SIGNAL),
      "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
      "stop",
      ngx_signal_handler },

    { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
      "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
      "quit",
      ngx_signal_handler },

    { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
      "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
      "",
      ngx_signal_handler },

    { SIGALRM, "SIGALRM", "", ngx_signal_handler },

    { SIGINT, "SIGINT", "", ngx_signal_handler },

    { SIGIO, "SIGIO", "", ngx_signal_handler },

    { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },

    { SIGSYS, "SIGSYS, SIG_IGN", "", NULL },

    { SIGPIPE, "SIGPIPE, SIG_IGN", "", NULL },

    { 0, NULL, "", NULL }
};

void
ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext)
{
    char            *action;
    ngx_int_t        ignore;
    ngx_err_t        err;
    ngx_signal_t    *sig;

    ignore = 0;

    err = ngx_errno;

	printf("signo = [%d]\n", signo);

    for (sig = signals; sig->signo != 0; sig++) {
        if (sig->signo == signo) {
            break;
        }
    }

    action = "";

    switch (ngx_process) {

    case NGX_PROCESS_MASTER:
    case NGX_PROCESS_SINGLE:
        switch (signo) {

        case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
            //ngx_quit = 1;
            action = ", shutting down";
            break;

        case ngx_signal_value(NGX_TERMINATE_SIGNAL):
        case SIGINT:
            //ngx_terminate = 1;
            action = ", exiting";
            break;

        case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
            /*
			if (ngx_daemonized) {
                ngx_noaccept = 1;
                action = ", stop accepting connections";
            }
			*/
            break;

        case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
            //ngx_reconfigure = 1;
            action = ", reconfiguring";
            break;

        case ngx_signal_value(NGX_REOPEN_SIGNAL):
            //ngx_reopen = 1;
            action = ", reopening logs";
            break;

        case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
			/*
            if (ngx_getppid() == ngx_parent || ngx_new_binary > 0) {

                action = ", ignoring";
                ignore = 1;
                break;
            }

            ngx_change_binary = 1;
			*/
            action = ", changing binary";
            break;

        case SIGALRM:
            //ngx_sigalrm = 1;
            break;

        case SIGIO:
            //ngx_sigio = 1;
            break;

        case SIGCHLD:
            //ngx_reap = 1;
            break;
        }

        break;

    case NGX_PROCESS_WORKER:
    case NGX_PROCESS_HELPER:
        switch (signo) {

        case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
            /*
			if (!ngx_daemonized) {
                break;
            }
            ngx_debug_quit = 1;
			*/
            /* fall through */
        case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
            //ngx_quit = 1;
            action = ", shutting down";
            break;

        case ngx_signal_value(NGX_TERMINATE_SIGNAL):
        case SIGINT:
            //ngx_terminate = 1;
            action = ", exiting";
            break;

        case ngx_signal_value(NGX_REOPEN_SIGNAL):
            //ngx_reopen = 1;
            action = ", reopening logs";
            break;

        case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
        case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
        case SIGIO:
            action = ", ignoring";
            break;
        }

        break;
    }

	/*
    if (siginfo && siginfo->si_pid) {
        printf("signal %d (%s) received from %P%s",
                      signo, sig->signame, siginfo->si_pid, action);

    } else {
        printf("signal %d (%s) received%s",
                      signo, sig->signame, action);
    }

	*/

    if (ignore) {
        printf("the changing binary signal is ignored: "
            "you should shutdown or terminate "
            "before either old or new binary's process");
    }
	printf("action = [%s]\n", action);
}


ngx_int_t
ngx_init_signals()
{
    ngx_signal_t      *sig;
    struct sigaction   sa;

    for (sig = signals; sig->signo != 0; sig++) {
        memset(&sa, 0x00, sizeof(struct sigaction));

        if (sig->handler) {
            sa.sa_sigaction = sig->handler;
            sa.sa_flags = SA_SIGINFO;

        } else {
            sa.sa_handler = SIG_IGN;
        }

        sigemptyset(&sa.sa_mask);
        if (sigaction(sig->signo, &sa, NULL) == -1) {
#if (NGX_VALGRIND)
            printf("sigaction(%s) failed, ignored", sig->signame);
#else
            printf("sigaction(%s) failed", sig->signame);
            return NGX_ERROR;
#endif
        }
    }

    return NGX_OK;
}

int main()
{
	//信号初始化
	ngx_init_signals();

#ifdef NOBLOCKFD
	testNonblockingSocketFd(fds);
#endif
	TDataExchangeChannel channels[GROUP_NUM];
	for (int i = 0; i < GROUP_NUM; i++) {
		socketpair(PF_UNIX, SOCK_STREAM, 0, channels[i].fds);
		int pid = fork();
		switch (pid) {
		case -1: // error
			return -1;
		case 0: // child
			childProcess(channels[i].fds, 2);
			printf("child exit \n");
			exit(0);
		default: // parent
			break;
		}
	}

	//父进程给子进程发送消息,并接收子进程发来的消息
	for (int i = 0; i < GROUP_NUM; i++) {
		parentProcess(channels[i].fds, 2);
	}

	while(1) {
		sleep(20);
	}
	return 0;
}

运行结果:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/603255.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据链路层:MAC地址

数据链路层&#xff1a;MAC地址&#xff08;以太网MAC子层所使用的地址&#xff09; 湖科大教书匠&#xff1a;MAC地址 声明&#xff1a;该学习笔记来自湖科大教书匠&#xff0c;笔记仅做学习参考 多主机连接在同一个广播信道上&#xff0c;要想实现两个主机之间的通信&#x…

MIUI系统降级刷机

成果图 解锁成功图 刷机确实成功了,不知道为什么显示失败的红色error,但是不影响使用 。 我的是小米平板5 Pro 刷机不是个简单的事情,有很多细节要注意,稍不留神手机就会变成砖,我见过好多人手机刷成砖,我无能为力,我也是个外行,自己多方面的了解许久之后,才开始对自…

你连存活到JDK8中著名的Bug都不知道,我怎么敢给你加薪

在笔者研究 JDK 源码时&#xff0c;注意到在CopyOnWriteArrayList 和ArrayList 的构造器中都出现了如下 bug 字样 6260652 其实代表的JDK bug 列表中的编号 http://bugs.java.com/bugdatabase/view_bug.do?bug_id6260652 http://bugs.java.com/bugdatabase/view_bug.do?bug…

【Leetcode60天带刷】day04链表——24. 两两交换链表中的节点, 19.删除链表的倒数第N个节点 ,面试题 02.07. 链表相交

题目&#xff1a;24. 两两交换链表中的节点 Leetcode原题链接&#xff1a;24. 两两交换链表中的节点 思考历程与知识点&#xff1a; 因为头结点没有前一个节点&#xff0c;所以为了让所有节点都能采用同一种调换方式&#xff0c;选择用虚拟头结点的写法。虚拟头结点可以理解…

英文论文(sci)解读复现【NO.16】OTA:目标检测的最优传输分配

此前出了目标检测算法改进专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读发表高水平学术期刊中的 SCI论文&a…

从零开始学习JavaScript:轻松掌握编程语言的核心技能③

从零开始学习JavaScript&#xff1a;轻松掌握编程语言的核心技能③ 一&#xff0c;JavaScript条件语句1.1 if...Else 语句1.2 if...else if...else 语句1.3 switch 语句1.4 for 循环1.5 while 循环 二&#xff0c;JavaScript break 和 continue 语句2.1 break语句2.2 continue语…

支付系统设计四:支付核心设计03-快捷短信确认(失败转代扣)

文章目录 前言一、快捷支付1. 执行流程1.1 发送短信1.1.1 发送短信(正常情况)1.1.2 发送短信(异常情况) 1.2 短信确认1.2.1 短信确认(正常情况)1.2.2 短信确认(异常情况) 2. 短信确认流程分析2.1 Service层执行2.2 快捷支付确认2.2.1 快捷支付确认命令链2.2.2 流程分析2.2.3 详…

Nacos 详解

Nacos是阿里的一个开源产品&#xff0c;是针对微服务架构中的服务发现、配置管理、服务治理的综合型解决方案。 1.1 什么是配置 应用程序在启动和运行的时候往往需要读取一些配置信息&#xff0c;配置基本上伴随着应用程序的整个生命周期&#xff0c;比如&#xff1a;数 据库…

istio证书异常

istio有时会出现证书异常的问题&#xff0c;例如证书校验失败&#xff0c;证书过期等&#xff0c;此时需要我们手动处理istio证书问题。 一、我的istio版本 client version: 1.3.3 control plane version: 1.3.3二、开始处理 1、先查询istio的密钥istio-ca-secret&#xff1a…

飞桨 GPU 训练

飞桨官网介绍使用流程 paddle —— 飞桨的深度学习核心框架本地 padddlepaddle 的安装和卸载安装查看当前安装的版本卸载 启动 GPU 训练指定 GPU 飞桨创建项目PaddlePaddle 2.1.2 下的对比修改为 paddlepaddle2.4.0 CUDA 飞桨 飞桨官网&#xff1a;https://www.paddlepaddle.o…

编程最重要的技术之一 — 调试(以C语言代码为例)

编程最重要的技术之一 — 调试&#xff08;以C语言代码为例&#xff09; 前言1. 什么是bug?2. 调试是什么&#xff1f;有多重要&#xff1f;2.1 调试是什么&#xff1f;2.2 调试的基本步骤2.3 Debug和Release的介绍 3. Windows环境调试介绍3.1 调试环境准备3.2 学会快捷键3.3 …

Unity - 记录解决 部分手机设备上 浮点精度 不足 导致 UV 采样断层严重的 BUG

文章目录 环境目的问题解决Project 环境 Unity : 2020.3.37f1 Pipeline : BRP 目的 备忘&#xff0c;便于日后索引 问题 正常手机显卡芯片的浮点解析进度上的效果&#xff08;其实不用手机上&#xff0c;PC 上将 uv * scale 一个巨大的值也会出现的&#xff09; 异常手机显…

MySql Order by 字段出现重复导致 limit 分页后的数据错乱

问题描述 select * from standard_process order by event_time desc 此条sql查询的结果如下&#xff1a; 共有28条数据&#xff0c;确实是按照event_time排序的。 但是加了limit以后就出现问题了&#xff0c;原本以为是截取的前10条&#xff0c;结果出现了数据错乱的情况。 …

安装VTK8.2.0-win 实际操作

Windows下安装VTK8.2.0 1、依赖 VS2017 Qt5 cmake 2、前期准备 2.1、访问vtk官方下载VTK8.2.0源码 VTK源码下载地址&#xff1a;https://vtk.org/download/ 2.2、配置环境变量 配置CMAKE_PREFIX_PATH&#xff0c;值为Qt的bin路径 2.3、新建2个文件夹一个用于存放cmake编…

Fourier分析入门——第14章——Fourier光学

目录 第14章 Fourier光学 14.1 引言 14.2 物理光学和图像形成(Physical optics and images formation) 14.3 Fourier光学域(The Fourier optics domain) 14.4 图像形成的线性系统描述(Linear Systems Description of Image Formation) 第14章 Fourier光学 14.1 引言 Four…

操作系统-进程和线程-进程和线程

目录 一、进程的概念、组成、特征 二、进程的状态与转换、组织 2.1进程状态 2.2进程转换关系 2.3进程的组织 链接方式 索引方式 三、进程控制 3.1进程的创建 3.2进程的终止 3.3进程的阻塞和唤醒 3.4进程的切换 ​编辑 四、进程通信 4.1共享存储 4.2消息传递 直接通信…

C++算法刷题--2023/6/2

源代码&#xff08;C&#xff09;&#xff1a; #include<iostream> using namespace std; struct Road{char way[100]{}; }; int main(){int t;cin>>t;struct Road *p new Road[t];int right0,left0;for(int i0;i<t;i){cin>>p[i].way;} for(int i0;i&…

力扣刷题【第一期】

文章目录 1.爬楼梯2.求两数的和&#xff08;283&#xff09;3.移动零&#xff08;283&#xff09;3.1 题目描述3.2 算法描述3.3具体实现 4.合并有序连表&#xff08;21&#xff09;4.1 题目描述4.2 算法思想4.3 代码实现 5.删除连表中重复的值&#xff08;83&#xff09;5.1 题…

CodeEditor之sublimetext:sublimetext的简介、安装、使用方法之详细攻略

CodeEditor之sublimetext&#xff1a;sublimetext的简介、安装、使用方法之详细攻略 目录 sublimetext的简介 sublimetext的安装 1、安装教程如下所示 sublimetext的使用方法 sublimetext的简介 Sublime Text 是一个文本编辑器&#xff08;收费软件&#xff0c;可以无限期试…

javascript基础十五:说说new操作符具体都干了什么?

一、是什么 在JavaScript中&#xff0c;new操作符用于创建一个给定构造函数的实例对象 举个粟子 function Parent (name,age){this.name name;this.age age; } undefined Parent.prototype.sayName function(){console.log(this.name) } ƒ (){console.log(this.name) } c…