百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

图解丨Nginx 中的四级指针

off999 2025-03-05 20:11 30 浏览 0 评论

Nginx的所有配置结构体全部放在一个cycle的四级指针中,本文就具体分析一下每级指针究竟指向的是什么,下图表示了这个四级指针每一级的指向,图中虚拟地址模拟了真实地址,ctx指针存的指向虚拟地址为1的数据,图中只列举出core,event,http模块最基础的配置结构。

需要注意得是,从图中不难发现,对于常用的模块,core模块,event模块,http模块,core模块只需要2级指针就能搞定,event模块按照逻辑只需要3级指针,而http模块需要4级指针。event按照常理缺少了http模块中间那个虚拟地址1000的结构体(区分main conf,serv conf,loc conf),需要3级指针就行。但是nginx为了方便配置,也在event模块中间也加入了类似的一个结构体指针(虚拟地址75存储100 的指针),不过这个指针直接指向了event模块的指针。这样event模块和http模块一样也形成了4级指针,这样设计event模块我认为是为了兼容http模块配置才形成了4级指针。


从代码切入,看一下ctx的初始化过程。


cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));


这段代码初始化了cycle的context,conf_ctx指向一段空间,每个地址存储void *的指针,这个指针能指向任何的一段空间,也就是各种conf结构体。

以下代码为第一层指针赋值,也就是每个conf_ctx每个空间存储第一层conf的结构体的首地址,这类conf的结构体不会包含event,http模块的,因为nginx并不确定配置一定有event和http模块的配置,所以在conf文件中没有碰到event和http的时候,是不会建立对应的结构体的。


for (i = 0; ngx_modules[i]; i++) {

 if (ngx_modules[i]->type != NGX_CORE_MODULE) { //加载core module,log module等

            continue;

 }



        module = ngx_modules[i]->ctx;



 if (module->create_conf) {

            rv = module->create_conf(cycle); //rv 是conf结构体首地址

 if (rv == NULL) {

                ngx_destroy_pool(pool);

                return NULL;

 }

            cycle->conf_ctx[ngx_modules[i]->index] = rv; //conf_ctx每个空间存储conf的首地址,构造了两层指针

 }

 }




下面的代码是解析command,获得这个command的conf结构体



if (cmd->type & NGX_DIRECT_CONF) {

                conf = ((void **) cf->ctx)[ngx_modules[i]->index]; //1



 } else if (cmd->type & NGX_MAIN_CONF) {

                conf = &(((void **) cf->ctx)[ngx_modules[i]->index]); //2



 } else if (cf->ctx) {

                confp = *(void **) ((char *) cf->ctx + cmd->conf); //3



 if (confp) {

                    conf = confp[ngx_modules[i]->ctx_index];

 }

 }



            rv = cmd->set(cf, cmd, conf);


1.NGX_DIRECT_CONF表示ngx_core_module,也就是配置中最外边配置的那些参数,因为 ngx_core_module,所对应的conf结构体,在初始化的时候已经创建好了,所以再ctx[index]的位 置是有conf的首地址的指针的,相当于图中虚拟地址50,后面在set command到结构体的时候,只需要把这个指针传过去就行了,这里ctx 2级指针是说明ctx一级指针指向的存储conf的首地址虚拟地址1,ctx二级指针指向conf的首地址,相当于图中虚拟地址50。 2.NGX_MAIN_CONF表示events http的配置,也就是说在cycle初始化的时候并不会初始化这些conf,前面说了因为我们根本不确定这些配置项是否真的有。所以在碰到events 或者http那种配置项的时候,那么就是初始化这一类配置项的时候,首先需要在ctx的相应位置赋值他们core conf module的结构体。因为之前ctx在这个位置并没有任何指向结构体的指针。所以把ctx位置的指针(虚拟地址2)赋值给conf,让后面的set函数,为这个位置赋值配置项结构体的首地址。

相关视频推荐

C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂

【文章福利】:小编整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!~点击加入(832218493需要自取)

对于第三个位置注释的代码说明,应该还是先说说event模块的加载,下面的代码是nginx events模块set函数

ctx = ngx_pcalloc(cf->pool, sizeof(void *)); //建立一个指针,虚拟地址75 (为了兼容http模块的4级指针的指针,图中红色的位置)

 if (ctx == NULL) {

        return NGX_CONF_ERROR;

 }



 *ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *)); //可以看到 event模块位置被赋值了一段空间,相当于ctx指向虚拟地址100,也就是虚拟地址75存储了100,相当于图中标黄色的过程1

 if (*ctx == NULL) {

        return NGX_CONF_ERROR;

 }



 *(void **) conf = ctx; //所以这里conf相当于虚拟地址2的地方存储是首地址为75的指针,相当于图中标红的过程2



 for (i = 0; ngx_modules[i]; i++) {

 if (ngx_modules[i]->type != NGX_EVENT_MODULE) {

            continue;

 }



        m = ngx_modules[i]->ctx;



 if (m->create_conf) {

 (*ctx)[ngx_modules[i]->ctx_index] = m->create_conf(cf->cycle); //相当于图中标绿的过程3

 if ((*ctx)[ngx_modules[i]->ctx_index] == NULL) { //相当于地址为100的位置存储首地址600,600是event core module的位置,虚拟地址101的地方存储首地址700,700是event epoll模块的结构体的首地址

                return NGX_CONF_ERROR;

 }

 }

 }



    pcf = *cf;

    cf->ctx = ctx; //重新赋值虚拟地址75的指针,继续解析配置。

    cf->module_type = NGX_EVENT_MODULE;

    cf->cmd_type = NGX_EVENT_CONF;



    rv = ngx_conf_parse(cf, NULL);


从上面的代码可以看出event模块的四级指针确实有些牵强,完全可以省略虚拟地址75位置的指针,虚拟地址2的位置直接存储100,不省略的原因正是前面说的原因,为了兼容http模块的配置,再看下http的代码




ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));

 if (ctx == NULL) {

        return NGX_CONF_ERROR;

 }



 *(ngx_http_conf_ctx_t **) conf = ctx; //相当于图中标红的过程1



    ngx_http_max_module = 0;

 for (m = 0; ngx_modules[m]; m++) {

 if (ngx_modules[m]->type != NGX_HTTP_MODULE) {

            continue;

 }



        ngx_modules[m]->ctx_index = ngx_http_max_module++;

 }



    ctx->main_conf = ngx_pcalloc(cf->pool,

                                 sizeof(void *) * ngx_http_max_module); //相当于图中标黄的过程2

 if (ctx->main_conf == NULL) {

        return NGX_CONF_ERROR;

 }

    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);

 if (ctx->srv_conf == NULL) {

        return NGX_CONF_ERROR;

 }



    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);

 if (ctx->loc_conf == NULL) {

        return NGX_CONF_ERROR;

 }



 for (m = 0; ngx_modules[m]; m++) {

 if (ngx_modules[m]->type != NGX_HTTP_MODULE) {

            continue;

 }



        module = ngx_modules[m]->ctx;

        mi = ngx_modules[m]->ctx_index;



 if (module->create_main_conf) {

            ctx->main_conf[mi] = module->create_main_conf(cf); //相当于图中标绿色的过程3

 if (ctx->main_conf[mi] == NULL) {

                return NGX_CONF_ERROR;

 }

 }


看完了上面http模块的初始化,应该就了解前面代码的用意:


  confp = *(void **) ((char *) cf->ctx + cmd->conf);



 if (confp) {

         conf = confp[ngx_modules[i]->ctx_index];

 }


在初始化完event模块之后,cf->ctx存储的就是75,event模块的cmd->conf都是0,因为这个cf->ctx一个兼容指针,所以confp指向的就是虚拟地址100,那么后面的代码根据模块的ctx_index就可以得到conf 了。

对于http模块cf->ctx存储的是1000,那么cmd->conf对于http模块不是0,在结构体ngx_http_conf_ctx_t中main,srv,loc有不同的位移,后面的逻辑和event一致,所以event模块的四级指针只是为了兼容http模块而多设了一层指针,那层指针充当了http指向ngx_http_conf_ctx_t结构体作用,这层对event模块是没有什么用的,对于http模块来说可以区分是main,srv,loc的配置。

相关推荐

百度手机卫士官网(百度手机卫士官网个人中心)

百度卫士  百度卫士是百度公司全新出品的简单可信赖的系统工具软件,集合了电脑加速、系统清理、木马查杀和软件管理功能,竭力为用户提供轻巧、快速、智能、纯净的产品体验。百度卫士郑重承诺:永久免费、不骚扰...

怎么自己安装win10系统(怎么自己安装win10系统)

 WindowS10安装系统教程方法很简单,建议使用U盘启动盘安装方法,找到一个8g的U盘,用老毛桃或大白菜启动程序制作成启动盘,将windowS10操作系统传入U盘内,插在电脑USB接...

win7升级win10需要产品密钥(windows7升级10要激活码吗)

1、通过win+R打开“运行”窗口,输入“cmd”打开命令提示窗口,输入slmgr/upk,卸载当初前操作系统密钥;  2、打开当前操作系统“系统盘”找内到“ESD”(升级助手缓存的windows...

华硕声卡驱动下载官网(华硕官方声卡驱动)

如果华硕笔记本声卡驱动消失了,可以尝试以下方法进行修复。首先,进入设备管理器,检查是否存在声卡设备,并进行更新驱动。如果没有找到声卡设备,可以在华硕官方网站上搜索相应型号的声卡驱动程序,并下载安装最新...

sd卡低级格式化(格式化 sd卡)

1.首先将装有内存卡的读卡器插到电脑主机USB接口中。2.接着点这里下载【内存卡低格工具llftool】工具。3.下载完成后,对其进行解压缩,然后双击运行其中的可执行程序。4.在打开的修复程序窗口中,...

怎么把一个u盘做成2个系统盘

1、U盘插入电脑,鼠标右键点击桌面的“此电脑”,选择管理。2、然后再选择“磁盘管理”。3、找到U盘的两个分区,选择一个不需要的分区,鼠标右键点击这个分区选择“删除卷”。4、删除完之后会出现一个未分配的...

华硕bios恢复出厂设置图解(华硕bios恢复出厂设置步骤)
华硕bios恢复出厂设置图解(华硕bios恢复出厂设置步骤)

可能有些人会不知道华硕笔记本怎么恢复出厂设置,现在给你们说说:华硕笔记本开机点击F2键即可进入BIOS界面,华硕主板可开机后点击DEL键进入BIOS界面。进入BIOS界面后,可通过以下两种方式恢复BIOS出厂设置:1、点击F9键后会出现以下...

2025-12-22 11:51 off999

平板电脑选择(平板电脑选择256还是512)

当选择平板电脑的存储容量时,以下是一些更具体的考虑因素:1.多媒体使用:如果你经常使用平板观看高清视频、存储大量照片或下载大型游戏,那么512GB的存储容量可能更适合你。这样你就可以存储更多的媒体文...

电脑主板天梯图2025最新版(主板天梯图2021最新)

笔记本电脑CPU天梯图,笔记本电脑CPU排行,是按照CPU的跑分进行排序,进行综合性能对比。可以一定程度上反应CPU的性能优劣,方便进行笔记本电脑CPU对比。2019年的CPU天梯图,基本是Intel...

电脑看视频一卡一卡的是什么原因

回答如下:可能是以下原因导致的:1.网络带宽不足:如果您的网络速度不够快,视频会一卡一卡的,因为您的电脑需要等待缓冲完成才能播放下一段视频。2.视频格式不受支持:如果您的电脑不支持视频格式,视频可...

qq官网下载2025最新版下载安装

现代ix35中控屏只需要连接WIFI就可以下载软件,下载之后再将应用安装好,就可以使用了一、电脑上下载当贝市场极速版(点击下载)到桌面上,接着拷贝到U盘里。二、在北京ix25汽车的中央控制屏上找到“设...

电脑玩游戏自动关机(电脑玩游戏自动关机内存条灯亮的)

1、解决病毒木马,修复系统受损的文件。2、检查硬件是不是有问题,重点检查主板、CPU风扇、主机电源供电情况,电源插座是不是有问题等。3、检查是不是有一些应用软件的任务完成后关机被启用了。这是可以明显的...

电脑重装系统从u盘启动怎么设置

答:第一步:老毛桃u盘制作1、准备一个老毛桃u盘启动盘制作工具,准备一个8G或以上容量的u盘。2、打开老毛桃u盘工具,确认识别u盘后,默认USB—HDD以及NTFS,点击一键制作成usb盘启动盘。3、...

office2016密钥激活码免费(office2016密钥激活码永久)

word2016激活密钥有两种类型:永久激活码和KMS期限激活密钥。其中,永久激活密钥可以使用批量授权版永久激活密钥进行激活,如所示;而KMS期限激活密钥需要使用KMS客户端密钥进行激活,如所示。另外...

免费html成品代码网站(html成品模板)
  • 免费html成品代码网站(html成品模板)
  • 免费html成品代码网站(html成品模板)
  • 免费html成品代码网站(html成品模板)
  • 免费html成品代码网站(html成品模板)

取消回复欢迎 发表评论: