Nginx单向链表 ngx_list_t

目录

基本概述

数据结构

接口描述

具体实现

ngx_list_create

ngx_list_init

ngx_list_push

使用案例


整理自 nginx 1.9.2 源码 和 《深入理解 Nginx:模块开发与架构解析》

基本概述

        Nginx 中的 ngx_list_t 是一个单向链表容器,链表中的每一个节点同时又是数据数组。ngx_list_t 作为链表容器,确定了 ngx_list_part_s 节点的存储空间容量、内存管理入口(内存池)和数据访问入口(链表+数组)。

        ngx_list_t  链表具体结构如下图所示。可灵活定义 ngx_list_part_s 中数据结构,同时因为其内部存储地址连续,可通过数组偏移进行快速访问。

数据结构

typedef struct ngx_list_part_s  ngx_list_part_t; 

/*
    链表中的一个节点,该节点中的 elts 记录一个数组的数据,数组类型可以自定义 ;
    节点使用的数组,容量(成员个数)已经固定(由 ngx_list_t 中的 nalloc 确定),
    使用 nelts 记录该数组已使用容量,所以 nelts 肯定小于 nalloc
*/
struct ngx_list_part_s { 
    void             *elts;   // 指向数组的起始地址。
    ngx_uint_t        nelts;  // 数组已使用了多少个元素
    ngx_list_part_t  *next;   // 下一个链表节点
};

/*
    ngx_list_part_s 链表容器,该结构体内确定了 ngx_list_part_s 的存储空间容量、内存管理入口和访问入口。
*/
typedef struct { 
    ngx_list_part_t  *last;  //指向链表的最后一个节点。
    ngx_list_part_t   part;  //链表的首个数组节点。
    // 限制 ngx_list_part_s elts 中每个数组元素的占用空间的大小
    size_t            size;  
    // 限制 ngx_list_part_s elts 中每个数组最大元素数量,一旦分配后是不可更改的
    ngx_uint_t        nalloc;
    // //链表中管理内存分配的内存池对象。用户要存放的数据占用的内存都是由 pool 分配的。
    ngx_pool_t       *pool;  
} ngx_list_t;

接口描述

// 创建新的链表,指定内存池对象,和数组容量(元素个数和每个元素大小)
// 该函数调用后会返回一个链表,该链表内至少有一个数组,不会是空链表的
ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);

// 初始化已有链表,与 ngx_list_create 使用方法相似,其实 ngx_list_create 里面也会调用 ngx_list_init
static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
    
// 往链表中新增元素,传入链表,返回新元素的首地址供使用。注意此时返回的是 ngx_list_part_s 中的 elts 成员
void *ngx_list_push(ngx_list_t *list);

具体实现

ngx_list_create

ngx_list_t *
ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size) //实际上就是为nginx_list_t的part成员创建指定的n*size空间,并且创建了空间sizeof(ngx_list_t)
{
    ngx_list_t  *list;

    // 分配 ngx_list_t 大小的内存
    list = ngx_palloc(pool, sizeof(ngx_list_t));
    if (list == NULL) {
        return NULL;
    }

    // 对空链表进行初始化
    if (ngx_list_init(list, pool, n, size) != NGX_OK) {
        return NULL;
    }

    return list;
}

ngx_list_init

static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    // 对链表的首个 ngx_list_part_s 元素中的数组分配内存,大小为 n * size,n 为数组元素个数,size 为数组内每个元素的大小,我们可以看到,这些配置在链表初始化的时候就已经写死了,不可再改变,除非再次初始化
    list->part.elts = ngx_palloc(pool, n * size); 
    if (list->part.elts == NULL) {
        return NGX_ERROR;
    }

    // 对链表的一些属性进行赋值
    list->part.nelts = 0;
    list->part.next = NULL;
    // 初始化时,链表只有一个节点,所以首节点也是末尾节点
    list->last = &list->part;
    list->size = size;
    list->nalloc = n;
    list->pool = pool;

    return NGX_OK;
}

ngx_list_push

// 往链表的末尾节点中新增数组,函数返回可用地址指针
void *
ngx_list_push(ngx_list_t *l)
{
    void             *elt;
    ngx_list_part_t  *last;

    last = l->last;

    // 判断末尾节点的数组空间是否满了
    if (last->nelts == l->nalloc) {

        /* the last part is full, allocate a new list part */
        // 若末尾节点空间满了,则往链表中新增节点,刷新末尾节点地址
        last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
        if (last == NULL) {
            return NULL;
        }

        last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
        if (last->elts == NULL) {
            return NULL;
        }
        // 新的末尾节点
        last->nelts = 0;
        last->next = NULL;
        // 刷新末尾节点指针,新节点变为末尾节点
        l->last->next = last;
        l->last = last;
    }

    elt = (char *) last->elts + l->size * last->nelts;
    last->nelts++;

    return elt;
}

使用案例

// 创建一个链表,链表中每个数组长度限制为 4,每个数组元素数据类型为 ngx_str_t
// 创建链表的时候,内部会调用 ngx_list_init
ngx_list_t* testlist = ngx_list_create(r->pool, 4, sizeof(ngx_str_t));
if (testlist == null )
{
    return NGX_ERORR;
}

// 往链表中添加数据,该数据会添加到链表末尾节点的数组中,若该数组剩余容量不足,会往链表中新增节点
ngx_str_t* str = ngx_list_push(testlist);
if ( str == null )
{
    return NGX_ERROR;
}
str->len = sizeof("hello world");
str->value = "he11o world";

// 遍历链表
// part 用于指向链表中的每一个 ngx_list_part_t 数组,刚开始执行链表中第一个节点
ngx_list_part_t* part = &testlist.part;
//根据链表中的数据类型,把数组里的 elts 转化为该类型使用
ngx_str_t* str = part->elts;
// i 表示元素在链表的每个 ngx_list_part_t 数组里的序号
for (i ; 0; /* void */; i++)
{
    // 如果数组已使用的数组元素已经遍历完,则需要跳转到链表中下一个节点
    if ( i >= part->nelts )
    {
        if ( part -> next == NULL )
        {
            // 如果某个 ngx_list_part_t 数组的 next 指针为空
            // 则说明已经遍历完链表了
            break;
        }

        // 访问下一个 ngx_list_part_t
        part = part->next;
        header = part->elts;

        // 将 i 序号置为 0,准备重新访问下一个数组
        i = 0;
    }
    // 遍历每个链表节点数组内的元素
    printf("list element : %*s\n", str[i].len, str[i].data);
}

------------------------------------以下为废话,不需要再阅读------------------------------------------

NGINX是一款高性能的HTTP服务器和反向代理服务器,它以其稳定性、丰富的功能集、以及轻量级架构而闻名。在互联网技术栈中,NGINX扮演着至关重要的角色,广泛应用于负载均衡、静态内容服务以及作为反向代理来提高应用的可用性和扩展性。它的事件驱动架构使其能够支持高并发连接,处理大量请求而不显著增加延迟。

NGINX的配置文件采用简洁明了的语法,使得用户可以轻松地进行性能调优和功能定制。通过模块化设计,NGINX不仅支持HTTP/2协议,还提供了对TLS/SSL的全面支持,确保数据传输的安全性。此外,它还具备WebSocket支持,使得实时通信应用能够无缝运行。

NGINX的反向代理能力尤为突出,它可以根据URL路径、头部信息等多种规则将客户端请求智能地转发到后端服务器群中的某一台或多台服务器上,实现请求的高效分发。同时,NGINX还支持健康检查机制,能够自动剔除故障节点,保证服务的高可用性。

对于静态内容的高效处理也是NGINX的一大亮点。它可以快速响应并交付HTML页面、图片、CSS文件等静态资源,极大地提升了网站访问速度。结合其缓存机制,NGINX能有效减轻后端服务器的压力,优化整体系统性能。

NGINX还提供了丰富的第三方模块,如安全防护、流量控制等,进一步增强了其功能性。无论是小型网站还是大型企业级应用,NGINX都能提供灵活且强大的解决方案,是现代Web架构中不可或缺的组成部分。

NGINX是一款高性能的HTTP服务器和反向代理服务器,它以其稳定性、丰富的功能集、以及轻量级架构而闻名。在互联网技术栈中,NGINX扮演着至关重要的角色,广泛应用于负载均衡、静态内容服务以及作为反向代理来提高应用的可用性和扩展性。它的事件驱动架构使其能够支持高并发连接,处理大量请求而不显著增加延迟。

NGINX的配置文件采用简洁明了的语法,使得用户可以轻松地进行性能调优和功能定制。通过模块化设计,NGINX不仅支持HTTP/2协议,还提供了对TLS/SSL的全面支持,确保数据传输的安全性。此外,它还具备WebSocket支持,使得实时通信应用能够无缝运行。

NGINX的反向代理能力尤为突出,它可以根据URL路径、头部信息等多种规则将客户端请求智能地转发到后端服务器群中的某一台或多台服务器上,实现请求的高效分发。同时,NGINX还支持健康检查机制,能够自动剔除故障节点,保证服务的高可用性。

对于静态内容的高效处理也是NGINX的一大亮点。它可以快速响应并交付HTML页面、图片、CSS文件等静态资源,极大地提升了网站访问速度。结合其缓存机制,NGINX能有效减轻后端服务器的压力,优化整体系统性能。

NGINX还提供了丰富的第三方模块,如安全防护、流量控制等,进一步增强了其功能性。无论是小型网站还是大型企业级应用,NGINX都能提供灵活且强大的解决方案,是现代Web架构中不可或缺的组成部分。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

KVM虚拟机管理脚本

思路: 在/opt/kvm下创建一个磁盘文件,做差异镜像,创建一个虚拟机配置文件,做虚拟机模版 [rootnode01 ~]# ls /opt/kvm/ vm_base.qcow2 vm_base.xml创建虚拟机的步骤:首先创建虚拟机的差异镜像,然后复制虚…

芯片Tapeout power signoff 之IR Drop Redhawk Ploc文件格式及其意义

数字IC后端工程师在芯片流程最后阶段都会使用redhawk或voltus进行设计的IR Drop功耗signoff分析。必须确保静态,动态ir drop都符合signoff标准。 在做redhawk ir drop分析前,我们需要提供一个redhawk ploc供电点坐标。 数字IC设计后端实现前期预防IR D…

流批一体向量化计算引擎 Flex 在蚂蚁的探索和实践

编者按:Flex是蚂蚁数据部自研的一款流批一体的向量化引擎,Flex是Fink和Velox的全称,也是Flexible的前缀,被赋予了灵活可插拔的寓意。本文将重点从向量化技术背景、Flex架构方案和未来规划三个方面展开论述。 作者介绍:…

Pytorch | 利用I-FGSSM针对CIFAR10上的ResNet分类器进行对抗攻击

Pytorch | 利用I-FGSSM针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集I-FGSSM介绍I-FGSSM代码实现I-FGSSM算法实现攻击效果 代码汇总ifgssm.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器: Pytorch | 从零构建AlexNet对CIFAR10进行分类 Pytorch…

全面Kafka监控方案:从配置到指标

文章目录 1.1.监控配置1.2.监控工具1.3.性能指标系统相关指标GC相关指标JVM相关指标Topic相关指标Broker相关指标 1.4.性能指标说明1.5.重要指标说明 1.1.监控配置 开启JMX服务端口:kafka基本分为broker、producer、consumer三个子项,每一项的启动都需要…

HTML制作一个普通的背景换肤案例2024版

一&#xff0c;完整的代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>换肤</t…

《计算机组成及汇编语言原理》阅读笔记:p86-p115

《计算机组成及汇编语言原理》学习第 6 天&#xff0c;p86-p115 总结&#xff0c;总计 20 页。 一、技术总结 1.if statement 2.loop 在许多编程语言中&#xff0c;有类种循环&#xff1a;一种是在程序开头检测条件(test the condition),另一种是在程序末尾检测条件。 3.C…

CSS(三)盒子模型

目录 Content Padding Border Margin 盒子模型计算方式 使用 box-sizing 属性控制盒子模型的计算 所有的HTML元素都可以看作像下图这样一个矩形盒子&#xff1a; 这个模型包括了四个区域&#xff1a;content&#xff08;内容区域&#xff09;、padding&#xff08;内边距…

MySQL外键类型与应用场景总结:优缺点一目了然

前言&#xff1a; MySQL的外键简介&#xff1a;在 MySQL 中&#xff0c;外键 (Foreign Key) 用于建立和强制表之间的关联&#xff0c;确保数据的一致性和完整性。外键的作用主要是限制和维护引用完整性 (Referential Integrity)。 主要体现在引用操作发生变化时的处理方式&…

MySQL从入门到入土---MySQL表的约束 (内含实践)---详细版

目录 引入&#xff1a; null 与not null default&#xff1a; comment列描述 &#xff1a; not null 和 default&#xff1a; zerofill &#xff1a; 主键&#xff1a;primary key 复合主键&#xff1a; 自增长:auto_increment 唯一键&#xff1a;unique key 外键&a…

基于NodeMCU的物联网窗帘控制系统设计

最终效果 基于NodeMCU的物联网窗帘控制系统设计 项目介绍 该项目是“物联网实验室监测控制系统设计&#xff08;仿智能家居&#xff09;”项目中的“家电控制设计”中的“窗帘控制”子项目&#xff0c;最前者还包括“物联网设计”、“环境监测设计”、“门禁系统设计计”和“小…

Webpack在Vue CLI中的应用

webpack 作为目前最流行的项目打包工具&#xff0c;被广泛使用于项目的构建和开发过程中&#xff0c;其实说它是打包工具有点大材小用了&#xff0c;我个人认为它是一个集前端自动化、模块化、组件化于一体的可拓展系统&#xff0c;你可以根据自己的需要来进行一系列的配置和安…

java日志框架:slf4j、jul(java.util.logging)、 log4j、 logback

SLF4J--抽象接口 SLF4J (Simple Logging Facade for Java) 是一个为各种 Java 日志框架提供简单统一接口的库。它的主要目的是将应用程序代码与具体的日志实现解耦&#xff0c;使得在不修改应用程序代码的情况下&#xff0c;可以轻松地切换不同的日志框架。 jul-to-slft4j.ja…

命令行之巅:Linux Shell编程的至高艺术(中)

文章一览 前言一、输入/输出及重定向命令1.1 输入/输出命令1.1.1 read命令1.1.2 echo命令 1.2 输入/输出重定向1.3 重定向深入讲解1.4 Here Document1.4.1 /dev/null 文件 二、shell特殊字符和命令语法2.1 引号2.1.1 双引号2.1.2 单引号2.1.3 倒引号 2.2 注释、管道线和后台命令…

一文理解机器学习中二分类任务的评价指标 AUPRC 和 AUROC

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 在机器学习的二分类任务中&#xff0c;评估模型性能是至关重要的一步。两种常用的评价指标是 Precision-Recall Curve 下的面积 (AUPRC) 和 Receiver Operating Characteristic Curve 下的面积 (AUROC)…

Visual Studio Code(VS Code)配置C/C++环境

一、Visual Studio Code安装 Visual Studio Code&#xff0c;下文中简称为VS Code的详细安装方法请参考VSCode安装教程&#xff08;超详细&#xff09;-CSDN博客 二、MinGW编译器下载与配置 1、MinGW介绍 MinGW(Minimalist GNU for Windows)是一款用于Windows 平台的轻…

少儿编程在线培训系统:客户服务与学习支持

2.1 VUE技术 VUE它是由HTML代码&#xff0c;配上嵌入在HTML代码里面的Java代码组成的应用于服务器端的语言&#xff0c;使用VUE进行开发能够更加容易区分网页逻辑以及网页设计内容&#xff0c;让程序员开发思路更加清晰化&#xff0c;VUE在设计组件时&#xff0c;它是可以重用的…

uniapp Native.js原生arr插件服务发送广播到uniapp页面中

前言 最近搞了个设备&#xff0c;需求是读取m1卡&#xff0c;厂家给了个安卓原生demo&#xff0c;接入arr插件如下&#xff0c;接入后发现还是少了一部分代码&#xff0c;设备服务调起后触发刷卡无法发送到uniapp里。 中间是一些踩坑记录&#xff0c;最后面是解决办法&#xf…

C项目 天天酷跑(下篇)

上篇再博客里面有&#xff0c;接下来我们实现我们剩下要实现的功能 文章目录 碰撞检测 血条的实现 积分计数器 前言 我们现在要继续优化我们的程序才可以使这个程序更加的全面 碰撞的检测 定义全局变量 实现全局变量 void checkHit() {for (int i 0; i < OBSTACLE_C…

HarmonyOS NEXT 实战之元服务:静态案例效果--航空出行

背景&#xff1a; 前几篇学习了元服务&#xff0c;后面几期就让我们开发简单的元服务吧&#xff0c;里面丰富的内容大家自己加&#xff0c;本期案例 仅供参考 先上本期效果图 &#xff0c;里面图片自行替换 效果图1完整代码案例如下&#xff1a; import { authentication } …