nginx系列第五篇:nginx中相关通信总结

news2024/11/25 8:22:13

目录

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

运行结果:

Linux下信号处理可以参考如下博客:

https://www.cnblogs.com/Alliswell-WP/p/CPlusPlus_Linux_07.html

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

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

相关文章

ThreeJS 炫酷特效旋转多面体Web页 Demo 01《ThreeJS 炫酷特效制作》

本案例为一个 threejs 的特效网页&#xff0c;大小球体进行包裹&#xff0c;外球体为透明材质&#xff0c;但是进行了线框渲染&#xff0c;使其能够通过外球踢查看其内球体。 注&#xff1a;案例参考源于互联网&#xff0c;在此做代码解释&#xff0c;侵删 本案例除 ThreeJS 外…

Kafka原理

生产者原理解析 生产者工作流程图&#xff1a; 一个生产者客户端由两个线程协调运行&#xff0c;这两个线程分别为主线程和 Sender 线程 。 在主线程中由kafkaProducer创建消息&#xff0c;然后通过可能的拦截器、序列化器和分区器的作用之后缓存到消息累加器&#xff08;Rec…

uniApp 页面通讯统一解决方案

文章目录 往期回顾统一解决方案uni.on和eventChannel之间的选择如何设置触发器最终范例距离 往期回顾 uniapp 踩坑记录 uni.$on为什么不能修改data里面的数据 uniApp页面通讯大汇总&#xff0c;如何页面之间传值 统一解决方案 uni.on和eventChannel之间的选择 uni.on和eve…

61082-041502PLF(0.80mm)40 位置 连接器 插座,G846A050210T1HR 集管和线壳 WTB 1.00 PITCH

61082-041502PLF&#xff08;0.80mm&#xff09;FCI紧凑型Bergstak连接器提供广泛的堆叠高度和电路尺寸&#xff0c;以支持广泛的夹层&#xff0c;板堆叠通信&#xff0c;数据和工业应用。 连接器类型&#xff1a;插座&#xff0c;外罩触点 针位数&#xff1a;40 间距&#xff…

浅谈互联网搜索之召回

一、背景 在搜索系统中&#xff0c;一般会把整个搜索系统划分为召回和排序两大子系统。本文会从宏观上介绍召回系统&#xff0c;并着重介绍语义召回。谨以此文&#xff0c;希望对从事和将要从事搜索行业的工作者带来一些启发与思考。 二、搜索系统召回方法 不同于推荐系统&…

6月6号软件资讯更新合集......

Yao 0.10.3 正式发布&#xff0c;拥抱 AIGC 时代&#xff01; ChatGPT 解锁了新的人机交互方式&#xff0c;人类可以与电脑直接交流了&#xff01;AIGC 时代已经到来&#xff0c;万千应用正在升级或重构&#xff0c;Yao 提供了一个开箱即用的解决方案&#xff0c;可以快速开发…

迷茫了3年:做完这个测试项目,我终于决定辞职!

2023年早已过半&#xff0c;来个迟到的年中总结&#xff0c;说实话&#xff0c;2023&#xff0c;很迷茫&#xff0c;然后过的非常不如意&#xff0c;倒不是上一年的职业目标没达到&#xff0c;而是接下来的路根本不知道如何走。在没解决这个问题之前&#xff0c;或者说没搞清楚…

Web3.0概念

学习web3您需要先掌握 JavaScript node React 后续 我们将学习一门新的语言 叫 Solidity 他是一种只能合约语言开发 我们利用web3将不再依赖后端 而是连接只能合约开发 首先 我们先不用急着写代码 还是要概念为先 首先 我们来对比 WEB1.0到3.0的概念 首先 web1.0 更多处于信…

AI实战营第二期——第一次作业:基于RTMPose的耳朵穴位关键点检测

题目&#xff1a;基于RTMPose的耳朵穴位关键点检测 背景 根据中医的“倒置胎儿”学说&#xff0c;耳朵的穴位反映了人体全身脏器的健康&#xff0c;耳穴按摩可以缓解失眠多梦、内分泌失调等疾病。耳朵面积较小&#xff0c;但穴位密集&#xff0c;涉及耳舟、耳轮、三角窝、耳甲…

Unity - 从RG中解压法线贴图

文章目录 环境目的问题解决References 环境 Unity : 2020.3.37f1 Pipeline : BRP 目的 备忘便于索引 问题 之前使用 GPA 还原一些效果的时候&#xff0c;发现 法线贴图的 Y 通道数值不对&#xff0c;感觉被 翻转了 比方说&#xff0c;下面是 GPA 中的法线 这个法线是 DX …

Ubuntu20.04安装EVO工具教程

EVO工具全名为“Python package for the evaluation of odometry and SLAM”&#xff0c;使用Python写的轨迹评估工具&#xff0c;目前在SLAM领域论文中的“使用率”逐渐上升&#xff0c;可以说已经成为了作为SLAMer一定要会用的工具。最近需要使用evo工具评测SLAM算法性能并可…

Dell服务器安装Ubuntu系统

1、下载镜像&#xff0c;做启动盘 镜像链接 http://old-releases.ubuntu.com/releases/20.04.2/ubuntu-20.04.2-live-server-amd64.iso 版本可以根据自己要求选择。 做启动盘 我用的是ultraiso 记得先格式化&#xff0c;再写入。 2、 设置BIOS启动 按F11&#xff0c;进入BIOS…

光线追踪是怎么影响渲染速度的,什么显卡可以支持?

在 3D 世界中&#xff0c;慢慢地人们倾向于让它尽可能逼真。他们可以应用许多技术和技巧&#xff0c;但有一种技术可以为您提供很多帮助&#xff0c;称为光线追踪。然而&#xff0c;众所周知&#xff0c;它是非常计算密集型的。在本文中&#xff0c;让我们进一步探讨它&#xf…

Java JUC并发编程

前言 1、JUC是指有关 java.util.concurrent包以及其子包&#xff0c;这些包都是有关线程操作的包 2、HTTPS服务请求中&#xff0c;WEB服务只负责创建主线程来接收外部的HTTPS请求&#xff0c;如果不做任何处理&#xff0c;默认业务逻辑是通过主线程来做的&#xff0c;如果业务…

Linux文件基础IO

目录 C文件IO相关操作 介绍函数 文件相关系统调用接口 接口介绍 fd文件描述符 重定向 缓冲区 inode 软硬链接 动静态库 库的制作 制作静态库 制作动态库 使用库 使用静态库 使用动态库 C文件IO相关操作 介绍函数 打开文件 参数介绍&#xff1a; const char*…

MySQL的explain字段解释

MySQL的explain字段解释 ,type类型含义:1.id 2.select_type 3.table 4.type(重要) 5.possible_keys 6.possible_keys 7. key 8.key_len 9. ref 10. rows(重要) 11. filtered 12. Extra(重要) 如下: Explain命令是查看查询优化器是如何决定执行查询的主要方法。这个功…

Firewalld防火墙详解

文章目录 Firewalld防火墙什么是防火墙Firewalld防火墙的概念Firewalld防火墙运行模式Firewalld防火墙的命令Firewalld防火墙的高级规则 Firewalld防火墙 什么是防火墙 防火墙&#xff1a;防范一些网络攻击。有软件防火墙、硬件防火墙之分。 硬件防火墙和软件防火墙的主要区…

【软件开发】MyBatis 理论篇

MyBatis 理论篇 1.MyBatis 是什么&#xff1f; MyBatis 是一个半 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;它内部封装了 JDBC&#xff0c;开发时只需要关注 SQL 语句本身&#xff0c;不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。…

初识网络之协议定制

目录 一、数据在网络传输中遇到的部分问题 1. 序列化与反序列化 2. 如何保证接收端读取一个完整的报文 二、实现一个简单的网络计算器 1. 客户端处理 1.1 请求结构体和返回结构体 1.2 解析输入的字符串 1.3 序列化 1.4 添加标识符和字符串长度 1.5 接收服务端返回的数…

浏览器的回流与重绘与事件循环

浏览器的回流与重绘和事件循环 浏览器回流浏览器重绘事件循环 浏览器回流 什么是浏览器回流&#xff1f; 回流是通过JS代码让布局或者几何属性改变&#xff0c;使部分页面或者整个页面更新的过程 浏览器重绘 剩下的是浏览器重绘&#xff1a;比如改变div的visibility, color、…