Nginx基础组件的使用
admin
2024-01-31 20:46:16
0

Nginx基础组件的使用

  • 一、Nginx 的相关组件介绍
    • 1.1、ngx_palloc相关源码
    • 1.2、ngx_array组件的相关源码
    • 1.3、ngx_array的数据结构
    • 1.4、ngx_cycle简介和相关源码
    • 1.5、ngx_list相关源码
    • 1.6、ngx_list 的数据结构
  • 二、Nginx 组件的使用
    • 2.1、makefile的编写
    • 2.2、ngx_palloc+ngx_array的使用
    • 2.3、ngx_palloc+ngx_list的使用
  • 总结
  • 后言

一、Nginx 的相关组件介绍

Nginx自己实现了一个内存池组件。Nginx作为服务器,当客户端 TCP连接 &HTTP请求 到来时,Nginx会为该连接创建一个专属的内存池;这个内存池的生命周期是连接建立时创建,连接断开时销毁。客户端和Nginx通信的所有数据和操作(HTTP协议解析、HTTP数据解析等)都在内存池中完成。

1.1、ngx_palloc相关源码

/src/core/ngx_palloc.h。(相关实现在/src/core/ngx_palloc.c文件)


#ifndef _NGX_PALLOC_H_INCLUDED_
#define _NGX_PALLOC_H_INCLUDED_#include 
#include /** NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.* On Windows NT it decreases a number of locked pages in a kernel.*/
#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)#define NGX_DEFAULT_POOL_SIZE    (16 * 1024)#define NGX_POOL_ALIGNMENT       16
#define NGX_MIN_POOL_SIZE                                                     \ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),            \NGX_POOL_ALIGNMENT)typedef void (*ngx_pool_cleanup_pt)(void *data);typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;struct ngx_pool_cleanup_s {ngx_pool_cleanup_pt   handler;void                 *data;ngx_pool_cleanup_t   *next;
};typedef struct ngx_pool_large_s  ngx_pool_large_t;struct ngx_pool_large_s {ngx_pool_large_t     *next;void                 *alloc;
};typedef struct {u_char               *last;u_char               *end;ngx_pool_t           *next;ngx_uint_t            failed;
} ngx_pool_data_t;struct ngx_pool_s {ngx_pool_data_t       d;size_t                max;ngx_pool_t           *current;ngx_chain_t          *chain;ngx_pool_large_t     *large;ngx_pool_cleanup_t   *cleanup;ngx_log_t            *log;
};typedef struct {ngx_fd_t              fd;u_char               *name;ngx_log_t            *log;
} ngx_pool_cleanup_file_t;ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
void ngx_destroy_pool(ngx_pool_t *pool);
void ngx_reset_pool(ngx_pool_t *pool);void *ngx_palloc(ngx_pool_t *pool, size_t size);
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
void ngx_pool_cleanup_file(void *data);
void ngx_pool_delete_file(void *data);#endif /* _NGX_PALLOC_H_INCLUDED_ */

/src/core/ngx_palloc.c

void *
ngx_array_push(ngx_array_t *a)
{void        *elt, *new;size_t       size;ngx_pool_t  *p;if (a->nelts == a->nalloc) {/* the array is full */size = a->size * a->nalloc;p = a->pool;if ((u_char *) a->elts + size == p->d.last&& p->d.last + a->size <= p->d.end){/** the array allocation is the last in the pool* and there is space for new allocation*/p->d.last += a->size;a->nalloc++;} else {/* allocate a new array */new = ngx_palloc(p, 2 * size);if (new == NULL) {return NULL;}ngx_memcpy(new, a->elts, size);a->elts = new;a->nalloc *= 2;}}elt = (u_char *) a->elts + a->size * a->nelts;a->nelts++;return elt;
}

/src/core/ngx_core.h

// ...
typedef struct ngx_pool_s            ngx_pool_t;
// ...

1.2、ngx_array组件的相关源码

/src/core/ngx_array.h


/** Copyright (C) Igor Sysoev* Copyright (C) Nginx, Inc.*/#ifndef _NGX_ARRAY_H_INCLUDED_
#define _NGX_ARRAY_H_INCLUDED_#include 
#include typedef struct {void        *elts;ngx_uint_t   nelts;size_t       size;ngx_uint_t   nalloc;ngx_pool_t  *pool;
} ngx_array_t;ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
void ngx_array_destroy(ngx_array_t *a);
void *ngx_array_push(ngx_array_t *a);
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{/** set "array->nelts" before "array->elts", otherwise MSVC thinks* that "array->nelts" may be used without having been initialized*/array->nelts = 0;array->size = size;array->nalloc = n;array->pool = pool;array->elts = ngx_palloc(pool, n * size);if (array->elts == NULL) {return NGX_ERROR;}return NGX_OK;
}#endif /* _NGX_ARRAY_H_INCLUDED_ */

1.3、ngx_array的数据结构

typedef struct {void        *elts;ngx_uint_t   nelts;size_t       size;ngx_uint_t   nalloc;ngx_pool_t  *pool;
} ngx_array_t;

elts:指向内存数据的指针。
nelts:指示已使用了多少个元素。
size:数组元素的大小。
nalloc:分配的元素数量。
pool:内存池。

array在内存里的布局:

0 : size1 : size2 : size... : sizenalloc -1 : sizengx_array_t

1.4、ngx_cycle简介和相关源码

Nginx的每个进程内部都有一个自己的ngx_cycle。

/src/core/ngx_cycle.h


#ifndef _NGX_CYCLE_H_INCLUDED_
#define _NGX_CYCLE_H_INCLUDED_#include 
#include #ifndef NGX_CYCLE_POOL_SIZE
#define NGX_CYCLE_POOL_SIZE     NGX_DEFAULT_POOL_SIZE
#endif#define NGX_DEBUG_POINTS_STOP   1
#define NGX_DEBUG_POINTS_ABORT  2typedef struct ngx_shm_zone_s  ngx_shm_zone_t;typedef ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, void *data);struct ngx_shm_zone_s {void                     *data;ngx_shm_t                 shm;ngx_shm_zone_init_pt      init;void                     *tag;ngx_uint_t                noreuse;  /* unsigned  noreuse:1; */
};struct ngx_cycle_s {// ...
};typedef struct {// ...
} ngx_core_conf_t;#define ngx_is_init_cycle(cycle)  (cycle->conf_ctx == NULL)ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle);
ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log);
void ngx_delete_pidfile(ngx_cycle_t *cycle);
ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig);
void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user);
char **ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last);
ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv);
ngx_cpuset_t *ngx_get_cpu_affinity(ngx_uint_t n);
ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name,size_t size, void *tag);
void ngx_set_shutdown_timer(ngx_cycle_t *cycle);extern volatile ngx_cycle_t  *ngx_cycle;
extern ngx_array_t            ngx_old_cycles;
extern ngx_module_t           ngx_core_module;
extern ngx_uint_t             ngx_test_config;
extern ngx_uint_t             ngx_dump_config;
extern ngx_uint_t             ngx_quiet_mode;#endif /* _NGX_CYCLE_H_INCLUDED_ */

1.5、ngx_list相关源码

/src/core/ngx_list.h


#ifndef _NGX_LIST_H_INCLUDED_
#define _NGX_LIST_H_INCLUDED_#include 
#include typedef struct ngx_list_part_s  ngx_list_part_t;struct ngx_list_part_s {void             *elts;ngx_uint_t        nelts;ngx_list_part_t  *next;
};typedef struct {ngx_list_part_t  *last;ngx_list_part_t   part;size_t            size;ngx_uint_t        nalloc;ngx_pool_t       *pool;
} ngx_list_t;ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t 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;
}/***  the iteration through the list:**  part = &list.part;*  data = part->elts;**  for (i = 0 ;; i++) {**      if (i >= part->nelts) {*          if (part->next == NULL) {*              break;*          }**          part = part->next;*          data = part->elts;*          i = 0;*      }**      ...  data[i] ...**  }*/void *ngx_list_push(ngx_list_t *list);#endif /* _NGX_LIST_H_INCLUDED_ */

1.6、ngx_list 的数据结构

typedef struct ngx_list_part_s  ngx_list_part_t;struct ngx_list_part_s {void             *elts;ngx_uint_t        nelts;ngx_list_part_t  *next;
};typedef struct {ngx_list_part_t  *last;ngx_list_part_t   part;size_t            size;ngx_uint_t        nalloc;ngx_pool_t       *pool;
} ngx_list_t;

elts:指向内存数据的指针。
nelts:指示已使用了多少个元素。
size:数组元素的大小。
nalloc:分配的元素数量。
pool:内存池。

list 在内存里的布局:

partpartngx_list_tpartpart*eltsnelts*next*eltsnelts*next*eltsnelts*next*lastsizenalloc*pool*eltsnelts*next

二、Nginx 组件的使用

Nginx的内存池分成大小块,小块是要么不释放要么全部释放。ngx_create_pool(size_t size, ngx_log_t *log)里的size就是用来区分大小块的,大于size的就是大块,否则就是小块。

2.1、makefile的编写

CXX = gcc
CXXFLAGS += -g -Wall -WextraNGX_ROOT = /home/fly/workspace/nginx-1.13.7TARGETS = ngx_code
TARGETS_C_FILE = $(TARGETS).cCLEANUP = rm -f $(TARGETS) *.oall: $(TARGETS)clean:$(CLEANUP)CORE_INCS = -I. \-I$(NGX_ROOT)/src/core \-I$(NGX_ROOT)/src/event \-I$(NGX_ROOT)/src/event/modules \-I$(NGX_ROOT)/src/os/unix \-I$(NGX_ROOT)/objs \-I$(NGX_ROOT)/../pcre-8.41 \-I$(NGX_ROOT)/../openssl-1.1.0g/include/ \NGX_PALLOC = $(NGX_ROOT)/objs/src/core/ngx_palloc.o
NGX_STRING = $(NGX_ROOT)/objs/src/core/ngx_string.o
NGX_ALLOC = $(NGX_ROOT)/objs/src/os/unix/ngx_alloc.o
NGX_ARRAY = $(NGX_ROOT)/objs/src/core/ngx_array.o
NGX_HASH = $(NGX_ROOT)/objs/src/core/ngx_hash.o
NGX_LIST = $(NGX_ROOT)/objs/src/core/ngx_list.o
NGX_QUEUE = $(NGX_ROOT)/objs/src/core/ngx_queue.o$(TARGETS): $(TARGETS_C_FILE)$(CXX) $(CXXFLAGS) $(CORE_INCS) $(NGX_PALLOC) $(NGX_STRING) $(NGX_ALLOC) $(NGX_ARRAY) $(NGX_LIST) $(NGX_QUEUE)  $(NGX_HASH) $^ -o $@

注意nginx的源码路径以及所需库的路径,要写正确的。

2.2、ngx_palloc+ngx_array的使用

示例代码:

#include #include "ngx_config.h"
#include "ngx_conf_file.h"
#include "nginx.h"
#include "ngx_core.h"
#include "ngx_string.h"
#include "ngx_palloc.h"
#include "ngx_array.h"
//#include "ngx_hash.h"typedef struct {int id;int level;
}ngx_fly_t;// 打印内存池的数据信息
void print_pool(ngx_pool_t *pool)
{while (pool){printf("avail pool memory size: %ld\n\n",pool->d.end - pool->d.last);pool=pool->d.next;}
}volatile ngx_cycle_t *ngx_cycle;#define unused(x)	(x)=(x)
void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,const char *fmt, ...)
{unused(level);unused(log);unused(err);unused(fmt);
}int main()
{ngx_str_t str = ngx_string("Hello World!");printf("string length: %ld\n", str.len);printf("string: %s\n", str.data);// 创建内存池ngx_pool_t *pool;pool = ngx_create_pool(1024, NULL);print_pool(pool);// 创建数组/** nalloc = 32* size = sizeof(ngx_fly_t)* pool = pool*/ngx_array_t *arr = ngx_array_create(pool, 32, sizeof(ngx_fly_t));print_pool(pool);ngx_fly_t *t1 = ngx_array_push(arr); // 拿出内存t1->id = 101;  //赋值t1->level = 1; //赋值print_pool(pool);ngx_fly_t *t2 = ngx_array_push(arr); // 拿出内存t2->id = 102;  //赋值t2->level = 3; //赋值print_pool(pool);return 0;
}

使用makefile来编译,执行结果:

$ ./ngx_codestring length: 12
string: Hello World!
avail pool memory size: 944avail pool memory size: 648avail pool memory size: 648avail pool memory size: 648

可以看到:

  1. 代码中分配的内存池是1024,分配之后只有944可以用,有80字节被使用了。这80字节其实是被内存池的头占用了(ngx_pool_t)。
  2. 分配完一个32的数组后,内存池还剩余的内存为648,也就是32*8=256被分配给了数据。
  3. 数组内存分配好之后,使用数组元素已经不会再去申请内存池的内存。
  4. 如果数组元素用完了,还调用ngx_array_push会怎么样?从ngx_array.c的源码中可以发现,它会动态扩容数组,重新分配2*size。

2.3、ngx_palloc+ngx_list的使用

示例代码:

#include #include "ngx_config.h"
#include "ngx_conf_file.h"
#include "nginx.h"
#include "ngx_core.h"
#include "ngx_string.h"
#include "ngx_palloc.h"
#include "ngx_array.h"
//#include "ngx_hash.h"typedef struct {int id;int level;
}ngx_fly_t;// 打印内存池的数据信息
void print_pool(ngx_pool_t *pool)
{while (pool){printf("avail pool memory size: %ld\n\n",pool->d.end - pool->d.last);pool=pool->d.next;}
}volatile ngx_cycle_t *ngx_cycle;#define unused(x)	(x)=(x)
void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,const char *fmt, ...)
{unused(level);unused(log);unused(err);unused(fmt);
}int main()
{ngx_str_t str = ngx_string("Hello World!");printf("string length: %ld\n", str.len);printf("string: %s\n", str.data);// 创建内存池ngx_pool_t *pool;pool = ngx_create_pool(1024, NULL);print_pool(pool);ngx_list_t *list=ngx_list_create(pool, 32, sizeof(ngx_fly_t));print_pool(pool);ngx_fly_t *t3 = ngx_list_push(list); // 拿出内存t3->id = 103;  //赋值t3->level = 3; //赋值print_pool(pool);ngx_fly_t *t4 = ngx_list_push(list); // 拿出内存t4->id = 104;  //赋值t4->level = 4; //赋值print_pool(pool);return 0;
}

使用makefile来编译,执行结果:

$ ./ngx_codestring length: 12
string: Hello World!
avail pool memory size: 944avail pool memory size: 632avail pool memory size: 632avail pool memory size: 632

可以发现,ngx_list相比ngx_array少了(648−632=16648-632=16648−632=16)字节,从源码的ngx_list_create()函数可以发现,是因为多了一个ngx_list_t的头数据。

总结

这里对ngx_string、ngx_array、ngx_list做了简单介绍和提供使用示例,其他的nginx基础组件的使用(比如dequeue、hash、log等等)也是类似的。

后言

本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对c/c++linux系统提升感兴趣的读者,可以点击链接,详细查看详细的服务:C/C++服务器课程

相关内容

热门资讯

火影安卓系统和ios系统互通吗... 你有没有想过,火影安卓系统和iOS系统之间是不是也能来个亲密接触呢?想象你可以在手机上随时随地,不管...
抽卡系统漫画app安卓,安卓用... 你有没有发现,最近手机上的一款漫画APP突然火了起来?没错,就是那个让人又爱又恨的抽卡系统!今天,就...
向葵视频安卓系统下载,轻松享受... 你有没有发现,最近手机上多了一个特别有趣的小玩意儿——向葵视频!这款视频软件可是火得一塌糊涂,不仅界...
安卓能登ios系统吗 你有没有想过,安卓手机能不能登录iOS系统呢?这个问题听起来是不是有点像是在问“猫能不能变成狗”一样...
荣耀如何玩好安卓系统,尽享流畅... 你有没有想过,为什么荣耀手机那么受欢迎呢?不仅仅是因为它的外观时尚,性能强大,更重要的是,它的安卓系...
安卓系统如何安装飞机,安卓系统... 你有没有想过,在安卓系统上安装飞机游戏,那感觉简直就像是真的驾驶了一架飞机在天空中翱翔!没错,今天就...
安卓系统大屏怎么恢复 手机屏幕突然变得模糊不清,是不是觉得自己的安卓大屏手机有点儿“老眼昏花”了呢?别急,今天就来教你怎么...
如何关闭安卓系统运行,轻松关闭... 手机用久了,是不是感觉安卓系统里的后台程序越来越多,运行速度越来越慢?别急,今天就来教你怎么关闭安卓...
安卓改苹果系统数据清理,系统数... 你是不是也和我一样,手机里堆满了各种应用,照片,视频,还有那些不知道什么时候开始占据空间的文件?别急...
锤子系统比安卓好吗,超越安卓的... 你有没有想过,手机系统到底哪家强?安卓和锤子系统,这两大巨头,哪个才是你的菜呢?今天,就让我来给你好...
安卓atv9.0系统,系统革新... 你有没有发现,最近安卓电视盒子界又掀起了一股热潮?没错,就是那款备受瞩目的安卓ATV9.0系统!今天...
安卓和苹果怎么转系统,安卓与苹... 你有没有想过,手机里的操作系统就像是个小世界,有时候你可能会想换个环境,体验一下不同的风景。没错,今...
苹果和安卓系统转换软件,苹果与... 你有没有想过,手机里的苹果和安卓系统,就像是两个截然不同的世界,各自有着独特的魅力和规则。但你知道吗...
找回安卓系统的软件,恢复系统至... 手机里的安卓系统是不是突然变得有点儿陌生了呢?是不是觉得那些曾经熟悉的软件都消失得无影无踪?别急,今...
安卓系统互相转移数据,轻松实现... 你有没有想过,当你从一台安卓手机换到另一台的时候,那些珍贵的照片、联系人、音乐和游戏怎么才能无缝转移...
安卓系统换几个桌面好用,让你的... 你有没有发现,手机桌面换换心情也是一种生活小情趣呢?尤其是安卓系统,桌面应用丰富,可玩性极高。今天,...
三星系统升级安卓系统 你知道吗?最近三星手机界可是热闹非凡呢!三星系统升级安卓系统,这可是个大新闻哦!想象你的三星手机瞬间...
安卓系统手绘软件推荐,安卓系统... 你有没有想过,用手机也能画出美美的画作呢?没错,现在就有这么神奇的安卓系统手绘软件,让你的创意随时随...
怎么升级htc安卓系统版本,版... 亲爱的手机控们,你是否也像我一样,对手机系统升级充满了期待和好奇呢?尤其是那些拥有HTC安卓手机的小...
三星系统最好的安卓系统 你有没有想过,为什么三星的安卓系统总是那么受欢迎呢?是不是每次看到三星手机,都会被那流畅的操作和丰富...