Nginx事件模块学习之连接

Nginx学习笔记(十九):Nginx连接 前言 上篇笔记记录了事件处理框架,以及事件的结构定义。这篇笔记开始Nginx连接定义。Nginx定义了基本的数据结构ngx_connection_t来表示连接,这类连接标识是由客户端主动发起、Nginx服务器被动接收的TCP连接,这类可以称为被动连接。还有一类连接,在某些请求的处理过程中,Nginx会试图主动向其他上游服务器建立连接,并以此连接与上游服务器通信,Nginx定义ngx_peer_c 阅读详情

        本节主要对最近学习的nginx事件模块做一下总结。通过对nginx整体的学习,觉得nginx的事件模块中管理连接的最主要的两个结构 ngx_connection_t,ngx_event_t,ngx_connection_t结构主要存储tcp连接结构, 对应ngx_event_t结构则存储对应位置上连接的读写事件。nginx的处理网络事件的事件模块可以配置,linux下默认用内核提供的epoll机制,epoll机制详情参见:Nginx事件模块学习之epoll_向往天空的鱼-优快云博客。

        对上述两个结构进行了简化,如下:

struct ngx_cycle_s {
	……
    ngx_connection_t         *free_connections;
    ngx_uint_t                free_connection_n;

    ngx_connection_t         *connections;
    ngx_event_t              *read_events;
    ngx_event_t              *write_events;
	……
}

struct ngx_connection_s {
    void               *data; // 空连接指向 next ;非空不同模块指的结构不同
    ngx_event_t        *read;
    ngx_event_t        *write;

    ngx_socket_t        fd;

    ngx_recv_pt         recv;
    ngx_send_pt         send;
	……

    ngx_listening_t    *listening;
	……
};

struct ngx_event_s {
    // 执行该事件所属的连接结构
    void            *data;
	……
};

        结构体之间的大致关系如下图:

        每次调用 ngx_get_connection 获取获取新连接时,该连接对应的读、写事件的data指针指向该连接。主要代码如下:

ngx_connection_t * ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
{
	……
    c = ngx_cycle->free_connections;
	
	……
    rev = c->read;
    wev = c->write;

	……
	// 该链接的读、写事件的data指针指向该连接
    rev->data = c;
    wev->data = c;

    return c;
}

        ngx_event_process_init函数主要代码如下:

static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle)
{
    ……
	// 申请连接对象存储
    cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);
    ……

	// 申请连接对象中读事件存储
    cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log);
	

	// 申请连接对象中写事件存储
    cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log);
    ……

	// 将上述申请的三个变量关联
    do {
        i--;
		
		// 连接数组中的每个(void *)data指针指向数组后一个ngx_connection_t结构的地址
        c[i].data = next;
		
		// 连接数组中的每个(ngx_event_t *)read、write指针指向 cycle->read_events、 cycle->write_events 数组对应位置的结构
        c[i].read = &cycle->read_events[i];
        c[i].write = &cycle->write_events[i];
		
        c[i].fd = (ngx_socket_t) -1;

        next = &c[i];
    } while (i);

	// 由于刚开始申请的连接全部还未被用,都为free状态
    cycle->free_connections = next;
    cycle->free_connection_n = cycle->connection_n;

    // 遍历全部的监听socket
    ls = cycle->listening.elts;
    for (i = 0; i < cycle->listening.nelts; i++) {

		……
        // 为其获取connection连接
		c = ngx_get_connection(ls[i].fd, cycle->log);
		
		……
		rev = c->read;
		
		……
        // 并为其读事件添加回调函数, tcp 为 ngx_event_accept
        rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept
                                                : ngx_event_recvmsg;

		……
        // 将监听套接字的读事件调用事件添加函数,添加至epoll中
        if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
            return NGX_ERROR;
        }
}

        上述ngx_event_process_init函数调用栈为:main() -> ngx_master_process_cycle() -> ngx_start_worker_processes() -> ngx_worker_process_cycle() -> ngx_worker_process_init();在ngx_worker_process_init函数中会调用所有模块的 init_process 函数指针,主要代码如下:

ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
{
	……
	for (i = 0; cycle->modules[i]; i++)
	{
		if (cycle->modules[i]->init_process)
		{
			if (cycle->modules[i]->init_process(cycle) == NGX_ERROR)
			{
				/* fatal */
				exit(2);
			}
		}
	}
	……
}

        上述了解到监听套接字的连接(ngx_connection_t)处理及回调函数(ngx_event_accept)的设置。

        当进程启动进程后,客户端的http请求nginx监听的端口时会触发监听套接字连接(ngx_connection_t)的读事件,进而调用读事件的handler处理函数(ngx_event_accept函数)去处理。函数主要代码如下:

void ngx_event_accept(ngx_event_t *ev)
{
	……
    lc = ev->data;
    ls = lc->listening;
    ……

    do {
        // 调用accept接收新连接
        s = accept(lc->fd, &sa.sockaddr, &socklen);

		// 新连接申请connection结构
        c = ngx_get_connection(s, ev->log);

        ……
        // 定义处理接收、发送数据的回调函数
        c->recv = ngx_recv;
        c->send = ngx_send;
        ……
		// 调用连接结构connection中listening结构的handler回调方法
        ls->handler(c);
		……
    } while (ev->available);
}

        由上述代码简单可知,当 ngx_event_accept 收到新连接时,最终会调用监听connection中listening结构的handler回调函数。该回调函数其实是在解析nginx配置文件时已被初始化;函数调用栈为: main() -> ngx_init_cycle() -> ngx_conf_parse() -> ngx_conf_handler();主要代码如下:

static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
    ……
	// 调用对应命令的set函数
    rv = cmd->set(cf, cmd, conf);
	
	……
}

        当解析到“http”关键字时,会调用对应的set回调函数:ngx_http_block。后续的函数栈调用为:ngx_http_block() -> ngx_http_optimize_servers() -> ngx_http_init_listening() -> ngx_http_add_listening。主要代码如下:

static ngx_listening_t * ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
{
	……
	
    ls = ngx_create_listening(cf, addr->opt.sockaddr, addr->opt.socklen);
    ……
	
	// 初始化 listen 结构的 handler 指针
    ls->handler = ngx_http_init_connection;

	……
}

       因此,当有客户端的新连接时会调用listen结构handler函数指针指向的函数: ngx_http_init_connection,该函数主要代码如下:

void ngx_http_init_connection(ngx_connection_t *c)
{
	// 申请 ngx_http_connection_t 结构
    hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t));
    c->data = hc;

    ……
	// 设置读、写事件的回调函数
    rev = c->read;
    rev->handler = ngx_http_wait_request_handler;
    c->write->handler = ngx_http_empty_handler;
	……
}

       ngx_http_init_connection() 函数主要设置了连接的读写事件的回调函数,当在该连接上接收或者发送数据时会调用回调。该函数主要代码如下:

static void ngx_http_wait_request_handler(ngx_event_t *rev)
{
	……
    c = rev->data;
	
	……
  
	// 调用c连接的revc回调函数接收数据,c->recv函数指针在ngx_event_accept函数值已被初始化
	// 根据系统不同调用不同函数,linux系统会调用ngx_unix_recv函数(封装了recv函数)
    n = c->recv(c, b->last, size);

	// 后续可以处理接收到的数据
    ……
}

        当一个客户端连接成功后,发送请求数据时,nginx会调用ngx_http_wait_request_handler() 函数接收数据。       

        而epoll机制是当内核发现有事件发生时调用对应事件的handler回调函数;主要实现函数ngx_epoll_process_events 的代码如下:

static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
    ……
    events = epoll_wait(ep, event_list, (int) nevents, timer);

	……
	// 遍历触发的事件
    for (i = 0; i < events; i++) {
	
        c = event_list[i].data.ptr;

		……
        rev = c->read;


        if ((revents & EPOLLIN) && rev->active) {
			……
			
			// 调用事件的handler回调函数
            rev->handler(rev);
			……
        }

     ……
	 }
}

        总结:nginx的ngx_connection_t*连接结构里面有两类连接,一类是:监听套接字的连接,该连接的回调函数为ngx_event_accept(); 另一类是:处理客户端数据的连接,该连接的回调函数为:ngx_http_wait_request_handler()。linux系统epoll机制监听所有的连接;当连接上有事件触发时调用该事件对应的回调函数。

nginx源码学习——Http连接对应的事件驱动模块 事件驱动函数事件驱动是nginx设计的核心,linux平台下,nginx会优先使用epoll进行事件处理。main—>master_process_cycle—>ngx_start_worker_process—>ngx_worker_process_cycle—>ngx_worker_process_init,ngx_process_events_and_timers。master进程中创建wor 阅读详情

相关推荐

Nginx十(阅读《深入理解nginx》总结之事件建立链接)

创作人QQ:851301776,邮箱:lfr890207@163.com,欢迎大家一起技术交流,本博客主要是自己学习的心得体会,只为每天进步一点点! 个人座右铭: 1.没有横空出世,只要厚积一定发。 2.你可以学历不高,你可以不上学,但你不能不学习 此博客总结,主要是方便日后查看学习 一、概述 Nginx的post事件处理机制。这个post事件是什么意思呢?它表示允许事件延后执行。Nginx设计了两个post队列,一个是由被触发的监听连接的读事件构成的ngx_posted_accept_events

weixin_43155199的博客 209

ngx_connection_t结构体

[cpp] view plain copy   //服务器的被动连接      struct ngx_connection_s {       //连接未使用时候,data域充当连接链表中的next指针.       //当连接被使用时候,data域的意义由模块而定.       void               *data;       //连接对应的

幽雨雨幽 1048

nginx stream proxy 模块的ssl连接源码分析

本为对 nginx的ngx_stream_proxy_module与上游服务器建立ssl连接的过程进行了详细分析。

一个致力于开源代码学习、分析和交流的博客 3331

【nginx】nginx常用的数据结构

nginx一些常用的数据结构体

weixin_43747685的博客 1296

【Nginx学习】深入 Nginx:4大步骤揭秘事件模块与事件处理框架

🔥关注墨瑾轩,带你探索编程的奥秘!🚀🔥超萌技术攻略,轻松晋级编程高手🚀🔥技术宝库已备好,就等你来挖掘🚀🔥订阅墨瑾轩,智趣学习不孤单🚀🔥即刻启航,编程之旅更有趣🚀。

java专栏 1237

【Nginx学习】深入 Nginx:6大步骤揭秘 ngx_events_module 核心模块如何管理所有事件模块的配置项

🔥关注墨瑾轩,带你探索编程的奥秘!🚀🔥超萌技术攻略,轻松晋级编程高手🚀🔥技术宝库已备好,就等你来挖掘🚀🔥订阅墨瑾轩,智趣学习不孤单🚀🔥即刻启航,编程之旅更有趣🚀。

java专栏 2072

Nginx源码解析——连接模块

由于 Nginx 工作在 master-worker 多进程模式,若所有 worker 进程在同一时间监听同一个端口,当该端口有新的连接事件出现时,每个worker 进程都会调用函数ngx_event_accept 试图与新的连接建立通信,即所有worker 进程都会被唤醒,这就是所谓的“惊群”问题,这样会导致系统性能下降。幸好在Nginx 采用了ngx_accept_mutex 同步锁机制,即只...

天行健,君子以自强不息 766

【Nginx学习】深入 Nginx:4大步骤揭秘 Nginx 连接的定义与主动连接处理

Nginx 作为高性能的 HTTP 和反向代理服务器,其连接处理机制不仅包括被动连接(如接受客户端连接),还包括主动连接(如向后端服务器发起请求)。本文将带你深入了解 Nginx 连接的定义与主动连接处理,通过代码和详细解析,让你在阅读后能够轻松掌握 Nginx 的连接处理机制。准备好了吗?让我们开始吧!在 Nginx 中,连接是用于处理客户端请求和后端服务器请求的基本单位。Nginx 使用结构体来表示连接,该结构体包含了连接的各种属性和方法。// 连接结构体// 日志对象// 文件描述符。

java专栏 1970

nginx 源码学习笔记(二十一)—— event 模块(二) ——事件驱动核心ngx_process_events_and_timers

首先继续回忆下,之前子线程执行操作里面有一个未涉及的内容ngx_process_events_and_timers,今天我们就来研究下这个函数。 本篇文章来自于:http://blog.youkuaiyun.com/lengzijian/article/details/7601730 先来看一下第十九节的部分截图: 今天主要讲解的就是事件驱动函数,图中的红色部分: src/event/ng

玩命写博客 1万+

Linux 系统管理员必备:Chrome 企业版离线部署全攻略(含 RPM/DEB 双版本)

本文详细介绍了Linux系统管理员如何离线部署Chrome企业版,涵盖RPM和DEB双版本。从获取官方离线安装包到静默安装、权限配置及企业级策略管理,提供全流程解决方案,特别适合Ubuntu等DEB系系统管理员参考。

f9g0h的博客 484

DroidGuard虚拟机逆向解析:指令集、密钥派生与反调试机制

DroidGuard是Google在Android生态中部署的轻量级定制虚拟机,用于设备完整性校验。其核心原理是通过自解释字节码、多层混淆指令集与动态密钥派生机制,在ART运行时构建静默安全沙箱。技术价值在于规避传统API检测盲区,实现高鲁棒性环境感知;典型应用场景包括金融SDK风控、Play Services可信启动及合规性审计。本文深入拆解其4字节指令编码规则、基于设备指纹的三阶段密钥派生(SHA256→Feistel→AES)、以及五层反调试体系(ptrace快照、时间差分、内存页探测、指令流校验、服

weixin_32736961的博客 587

Nginx企业级负载均衡:技术详解系列(9)—— Nginx核心配置详解(全局配置)

默认Nginx是不进行多进程绑定的,绑定并不是意味着当前nginx进程独占一核心CPU,但是可以保证此进程不会运行在其他核心上,这就极大减少了nginx的工作进程在不同的CPU核心上来回跳转,减少了CPU对进程资源分配与回收以及内存管理等。:worker_rlimit_nofile 所有worker进程能打开的文件数量上限,包括:Nginx的所有连接(例如与代理服务器的连接数),而不仅仅是客户端的连接,另一个考虑因素是实际的并发连接数不能超过系统级别的最大打开文件数的限制。

趙兴晨的博客 1613

用AI画电路板AI EDA初探Creating WiFi Radio with CELUS: A Step-by-Step Tutorial 使用CELU.IO创建WiFi收音机:分步教程

结论:整体还不太成熟,所选器件单元是欧美思维,器件选型成本和咱们华强北还是无法比。可以关注迭代,看客就当走马观花就行了;不过里面的单元模块还带有AI提问的这个比较好,值得国内EDA从业者学习。话不多说上正文:本教程目的是让我们深入了解如何使用CELUS设计平台构建WiFi收音机实战项目。本指南的重点是使用该平台来选择正确的解决方案,并整合一个项目,让您可以将音乐和节目从互联网直接传输到您自己构建的扬声器。

2301_81235726的博客 1万+

nginx 源码学习笔记(二十一)—— event 模块(二) ——事件驱动核心ngx_process_events_and_timers...

首先继续回忆下,之前子线程执行操作里面有一个未涉及的内容ngx_process_events_and_timers,今天我们就来研究下这个函数。 本篇文章来自于:http://blog.youkuaiyun.com/lengzijian/article/details/7601730 先来看一下第十九节的部分截图: 今天主要讲解的就是事件驱动函数,图中的红色部分: src/event/ngx_...

数据库天地 414

数字IC设计技能篇之如何在RTL级降低功耗?

以上就是本次降低芯片功耗的部分心得和收获,由于是在芯片设计阶段还没办法后端直接给出power的报告,前端一般使用spyglass和fsdb来进行功耗分析,后续会更新如何使用spyglass在前仿阶段进行power的分析,以及持续更新有关RTL级降低功耗的相关内容。

mzynk的博客 1202

汇丰外包Java岗面试复盘:Zoom面1.5小时,从英语、粤语到现场敲代码的极限挑战

本文详细记录了汇丰银行外包Java岗位的面试全过程,包括多语言切换(英语、粤语)的技术沟通挑战和现场编码测试的实战经验。从高并发编程到JVM调优,面试不仅考察技术深度,更注重实战问题解决能力。文章分享了应对跨国银行技术面试的实用策略,帮助Java开发者在跨文化环境中提升竞争力。

weixin_42524824的博客 363

nginx怎么控制socket链接转发到某台服务器_了解 Nginx 的基本概念

前言本篇是我学习Nginx的一些笔记,主要内容讲述了一些了解Nginx需要的基本概念。 然后探讨一下Nginx的模块化的组织架构,以及各个模块的分类、工作方式、职责和提供的相关指令。 主要达到以下目的:了解Nginx的大概运行原理了解Nginx的基本概念知道怎么看官方文档。关于NginxNginx是一款面向性能设计的HTTP服务器,能反向代理HTTP,HTTPS和邮件相关(SMTP,POP3,IM...

weixin_39610759的博客 477

机器学习实战——疫情数据分析与预测

机器学习如何做到疫情可视化——疫情数据分析与预测实战 本文将带领大家爬取11个国家以及中国31个省(自治区、直辖市)在2022.0101-2022.06.19的新冠疫情数据。并且采用机器学习模型对2022.6.20-2022.6.30每一天的全国确诊人数、死亡人数、治愈人数进行预测,**做出疫情可视化图形并且求出最终的相关系数R2!...

拥有百余位万粉技术博主、200余位可合作代发博主,私域技术社群规模达千人,商务合作私信 10万+

nginx学习手札(一)简单配置

首先需要安装PCRE包,为的是让nginx支持正则表达式: 下载地址:ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-7.7.tar.gz 安装很简单,./configure&& make&&make install即可 nginx的安装就不赘述了,网上到处都有,我的编译参数是: ./configure --with

黑鹰 605

雷赛控制卡的扩展IO连接

因设备的上IO点较多,所以使用了多个雷赛32点位的IO扩展卡。上位机程序在控制输出IO时发现主模块IO和第一个扩展IO的输出可以控制。但第二个IO扩展卡和第三个IO扩展卡的输出控制不了。经排查出发现轴卡在初始化时只连接了第一个扩展IO卡。增加下面的代码连接上扩展IO就可以了。雷赛控制卡的扩展IO点无法控制问题处理。

StevenChen的博客 3169

9篇3章7节:基于 R 语言的 FAERS 数据提取与合并

本文主要探讨了 FAERS 数据提取与合并的操作流程。首先,通过程序化方法从本地存储的 FAERS ASCII 文件中提取指定季度或范围内的单药报告数据,并可通过参数设置控制数据存储位置、处理方式、计算资源分配以及报告者职业类别等。随后,通过批量读取的方式对多个季度的 DRUG 文件进行循环处理,并将其合并为一个综合数据框。

MD Code 1262

利用nginx的事件模型开发自己的应用

Nginx拥有大名鼎鼎的事件模型,在初始化介绍后循环调用ngx_process_events_and_timers(cycle),来处理各种事件。并且其高效的时间模块,能很方便地控制各event的超时等。 这样的一套机制,不仅适用于http,mail等应用,甚至我们可以不管nginx里的网络功能,利用这套event机制,开发一个本地的小应用。这样做很好玩,也可以更好的学习nginx的事件、时间模

zhaomangzheng的专栏 862

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Nginx这么香,还不知道怎么学?看完这份Nginx笔记你能立马上手

从3个层次上介绍Nginx的进程模型.首先是最顶层,通过Nginx整体架构框图从宏观上了解Nginx:其次是中间层,对监控进程、工作进程、Cache进程进行逐一介绍,了解它们各自的主要执行逻辑最后是交互层,即进程之间(套接字、共享内存)以及进程与用户之间(信号)的信息交换.Nginxft供的丰富功能基本都是通过模块来实现的,根据每个模块的具体功能不同而分为不同的类型,比如Handler模块、Filter模块、Load-balance模块等.通过对它们的综合描述,从宏观上了解每类Nginx模块的功能。

jjc4261的博客 200

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: 透明代理(NAT)
下一篇: Nginx数据结构学习
码农诗人
博客等级 码龄11年 987粉丝 84原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值