Ubuntu 下 nginx-1.24.0 源码分析 (1)
main 函数在
src\core\nginx.c
int ngx_cdecl
main(int argc, char *const *argv)
{ngx_buf_t *b;ngx_log_t *log;ngx_uint_t i;ngx_cycle_t *cycle, init_cycle;ngx_conf_dump_t *cd;ngx_core_conf_t *ccf;ngx_debug_init();
进入 main 函数
最开始是局部变量的声明
然后是
ngx_debug_init();
接下来是 :
if (ngx_strerror_init() != NGX_OK) {return 1;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_strerror_init()函数-CSDN博客
接下来是 :
if (ngx_get_options(argc, argv) != NGX_OK) {return 1;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_get_options函数-CSDN博客
当前这次执行的是:
sudo ./nginx
除了 程序名 没有其他参数
所以
argc=1
于是在 ngx_get_options 函数中
static ngx_int_t
ngx_get_options(int argc, char *const *argv)
{u_char *p;ngx_int_t i;for (i = 1; i < argc; i++) {p = (u_char *) argv[i];if (*p++ != '-') {ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]);return NGX_ERROR;}while (*p) {switch (*p++) {case '?':case 'h':ngx_show_version = 1;ngx_show_help = 1;break;case 'v':ngx_show_version = 1;break;case 'V':ngx_show_version = 1;ngx_show_configure = 1;break;case 't':ngx_test_config = 1;break;case 'T':ngx_test_config = 1;ngx_dump_config = 1;break;case 'q':ngx_quiet_mode = 1;break;case 'p':if (*p) {ngx_prefix = p;goto next;}if (argv[++i]) {ngx_prefix = (u_char *) argv[i];goto next;}ngx_log_stderr(0, "option \"-p\" requires directory name");return NGX_ERROR;case 'e':if (*p) {ngx_error_log = p;} else if (argv[++i]) {ngx_error_log = (u_char *) argv[i];} else {ngx_log_stderr(0, "option \"-e\" requires file name");return NGX_ERROR;}if (ngx_strcmp(ngx_error_log, "stderr") == 0) {ngx_error_log = (u_char *) "";}goto next;case 'c':if (*p) {ngx_conf_file = p;goto next;}if (argv[++i]) {ngx_conf_file = (u_char *) argv[i];goto next;}ngx_log_stderr(0, "option \"-c\" requires file name");return NGX_ERROR;case 'g':if (*p) {ngx_conf_params = p;goto next;}if (argv[++i]) {ngx_conf_params = (u_char *) argv[i];goto next;}ngx_log_stderr(0, "option \"-g\" requires parameter");return NGX_ERROR;case 's':if (*p) {ngx_signal = (char *) p;} else if (argv[++i]) {ngx_signal = argv[i];} else {ngx_log_stderr(0, "option \"-s\" requires parameter");return NGX_ERROR;}if (ngx_strcmp(ngx_signal, "stop") == 0|| ngx_strcmp(ngx_signal, "quit") == 0|| ngx_strcmp(ngx_signal, "reopen") == 0|| ngx_strcmp(ngx_signal, "reload") == 0){ngx_process = NGX_PROCESS_SIGNALLER;goto next;}ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal);return NGX_ERROR;default:ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));return NGX_ERROR;}}next:continue;}return NGX_OK;
}
进入不了 for 循环
直接走到
return NGX_OK;
返回到 main 函数中
接下来是 :
if (ngx_show_version) {ngx_show_version_info();if (!ngx_test_config) {return 0;}}
ngx_show_version 未设置,此时是 0
于是跳过这段代码
接下来是 :
/* TODO */ ngx_max_sockets = -1;
初始化全局变量 ngx_max_sockets
ngx_max_sockets
是一个全局变量,用于存储 Nginx 能够处理的最大文件描述符(socket)数量。
文件描述符是操作系统用于管理打开的文件、socket 等资源的标识符。Nginx 作为一个高性能的 Web 服务器,需要处理大量的并发连接,因此文件描述符的数量对性能有重要影响
初始值为 -1
的意义
-
将
ngx_max_sockets
初始化为-1
表示在程序启动时,还没有确定实际的最大文件描述符数量。 -
-1
通常用作一个初始值或无效值,表示该变量尚未被正确初始化或配置。 -
在后续的代码中,Nginx 会根据操作系统的限制和配置文件中的设置来更新
ngx_max_sockets
的值。
接下来是 :
ngx_time_init();
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_time_init 函数-CSDN博客
接下来是 :
#if (NGX_PCRE)ngx_regex_init();
#endif
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_regex_init 函数-CSDN博客
接下来是 :
ngx_pid = ngx_getpid();ngx_parent = ngx_getppid();
获取当前进程的进程ID(ngx_pid
)和父进程的进程ID(ngx_parent
)。
这在后续的进程管理中很有用。
在 src/os/unix/ngx_process.h 中:
#define ngx_getpid getpid
#define ngx_getppid getppid
getpid
和getppid
是 C 语言中用于获取进程 ID 的函数,定义在<unistd.h>
头文件中getpid():获取当前进程的进程ID
getppid():获取当前进程的父进程ID父进程是创建当前进程的进程(如通过fork())。
若父进程终止,子进程的PPID会被重置为init进程(PID=1)
接下来是:
log = ngx_log_init(ngx_prefix, ngx_error_log);if (log == NULL) {return 1;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_log_init 函数-CSDN博客
此次调用 ngx_log_init 时
prefix 和 error_log 都还没有设置此时还是 null
进入 ngx_log_init
首先是
ngx_log_t *
ngx_log_init(u_char *prefix, u_char *error_log)
{u_char *p, *name;size_t nlen, plen;ngx_log.file = &ngx_log_file;ngx_log.log_level = NGX_LOG_NOTICE;
-
将全局日志对象
ngx_log
的文件指针指向ngx_log_file
。 -
设置默认日志级别为
NGX_LOG_NOTICE
(通知级别)
if (error_log == NULL) {error_log = (u_char *) NGX_ERROR_LOG_PATH;}name = error_log;nlen = ngx_strlen(name);
此时 error_log 还是null
于是进入这个 if 条件中
把默认值 NGX_ERROR_LOG_PATH 赋值给 error_log
这个默认值是在 执行configure命令时定义的一个宏,它的值由 configure 命令的配置项 --error-log-path 指定
if (nlen == 0) {ngx_log_file.fd = ngx_stderr;return &ngx_log;}p = NULL;
nlen 不是0
跳过这个 if 条件
if (name[0] != '/') {
检查路径是否以 /
开头
是以 /
开头
所以当前 name 已经是绝对路径了,不需要拼接前缀
ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND,NGX_FILE_CREATE_OR_OPEN,NGX_FILE_DEFAULT_ACCESS);
以追加的方式打开 name 指向的 日志文件
此时返回的 fd 是 4
if (ngx_log_file.fd == NGX_INVALID_FILE) {ngx_log_stderr(ngx_errno,"[alert] could not open error log file: "ngx_open_file_n " \"%s\" failed", name);
NGX_INVALID_FILE 的值是 -1 无效的文件描述符,表示上一步的打开文件失败
现在这个条件不成立,跳过这段代码
if (p) {ngx_free(p);}return &ngx_log;
由于之前条件不成立,所以 没有用到 p
最后返回 ngx_log 的地址
回到 main 函数中
接下来是:
ngx_ssl_init(log);
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_ssl_init 函数-CSDN博客
接下来是:
ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
把 init_cycle 的每个字节都初始化为 0
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_cycle_t 类型-CSDN博客
init_cycle.log = log;
将之前 初始化的 日志对象的地址 记录在 log 字段
ngx_cycle = &init_cycle;
现在 ngx_cycle 是指向 init_cycle 的指针了
init_cycle.pool = ngx_create_pool(1024, log);
创建一个内存池要求的内存大小是 1024 字节,然后将地址记录到 init_cycle 的 pool 字段进行管理
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_create_pool函数-CSDN博客
进入 ngx_create_pool
ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log)
{ngx_pool_t *p;p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);if (p == NULL) {return NULL;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_memalign函数-CSDN博客
使用 ngx_memalign 来分配内存
NGX_POOL_ALIGNMENT 是要求的对齐边界,值为 16
进入 ngx_memalign
void *
ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
{void *p;int err;err = posix_memalign(&p, alignment, size);
调用 posix_memalign 来分配一块对齐的内存
posix_memalign 函数-CSDN博客
此次返回值为 0
也就是分配内存成功了
p=0x5aa55f9765a0
这个地址是按 16 对齐的
if (err) {ngx_log_error(NGX_LOG_EMERG, log, err,"posix_memalign(%uz, %uz) failed", alignment, size);p = NULL;}
条件不成立,跳过这段代码
return p;
把分配的地址返回到
ngx_create_pool 函数中
回到 ngx_create_pool
接下来是:
if (p == NULL) {return NULL;}
条件不成立,跳过这段代码
p->d.last = (u_char *) p + sizeof(ngx_pool_t);p->d.end = (u_char *) p + size;p->d.next = NULL;p->d.failed = 0;size = size - sizeof(ngx_pool_t);p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;p->current = p;p->chain = NULL;p->large = NULL;p->cleanup = NULL;p->log = log;return p;
赋值然后返回 内存池 地址
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_create_pool函数-CSDN博客
当前 size = 944 , NGX_MAX_ALLOC_FROM_POOL = -1
所以 p->max=944
回到 main 函数中
接下来是:
if (init_cycle.pool == NULL) {return 1;}
条件不成立,跳过这段代码
if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {return 1;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_save_argv函数-CSDN博客
if (ngx_process_options(&init_cycle) != NGX_OK) {return 1;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_process_options-CSDN博客
进入 ngx_process_options
static ngx_int_t
ngx_process_options(ngx_cycle_t *cycle)
{u_char *p;size_t len;if (ngx_prefix) {
ngx_prefix 还是 null
所以跳过这个 if 代码段进入 else
接下来是:
ngx_str_set(&cycle->conf_prefix, NGX_CONF_PREFIX);
将 默认的配置文件路径前缀设置给 cycle->conf_prefix
ngx_str_set(&cycle->prefix, NGX_PREFIX);
将 默认的路径前缀设置给 cycle->prefix
if (ngx_conf_file) {cycle->conf_file.len = ngx_strlen(ngx_conf_file);cycle->conf_file.data = ngx_conf_file;} else {ngx_str_set(&cycle->conf_file, NGX_CONF_PATH);}
此次启动没有指定 配置文件路径
所以 ngx_conf_file 在这里还是 null
进入 else 中,将 默认的配置文件路径设置给 cycle->conf_file 进行管理
接下来是:
if (ngx_conf_full_name(cycle, &cycle->conf_file, 0) != NGX_OK) {return NGX_ERROR;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_conf_full_name 函数-CSDN博客
cycle->conf_file 保存的配置文件路径可能是 相对路径,需要 调用 ngx_conf_full_name 来拼接路径前缀 然后形成完成的路径
进入 ngx_conf_full_name 中
ngx_int_t
ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix)
{ngx_str_t *prefix;prefix = conf_prefix ? &cycle->conf_prefix : &cycle->prefix;return ngx_get_full_name(cycle->pool, prefix, name);
}
这里传进来的 conf_prefix 的值是 0
所以 prefix = &cycle->prefix; 选择 cycle->prefix (/usr/local/nginx/) 作为配置文件路径前缀
然后调用 ngx_get_full_name 来拼接路径
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_get_full_name 函数-CSDN博客
进入 ngx_get_full_name
ngx_int_t
ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix, ngx_str_t *name)
{size_t len;u_char *p, *n;ngx_int_t rc;rc = ngx_test_full_name(name);if (rc == NGX_OK) {return rc;}
调用 ngx_test_full_name 来判断 name (/home/wsd/桌面/nginx/conf/nginx.conf) 是否是完整的路径
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_test_full_name-CSDN博客
进入 ngx_test_full_name
static ngx_int_t
ngx_test_full_name(ngx_str_t *name)
{
#if (NGX_WIN32)u_char c0, c1;c0 = name->data[0];if (name->len < 2) {if (c0 == '/') {return 2;}return NGX_DECLINED;}c1 = name->data[1];if (c1 == ':') {c0 |= 0x20;if ((c0 >= 'a' && c0 <= 'z')) {return NGX_OK;}return NGX_DECLINED;}if (c1 == '/') {return NGX_OK;}if (c0 == '/') {return 2;}return NGX_DECLINED;#elseif (name->data[0] == '/') {return NGX_OK;}return NGX_DECLINED;#endif
}
当前环境是 Ubuntu #if (NGX_WIN32) 不成立
所以接下来执行的是:
if (name->data[0] == '/') {return NGX_OK;}return NGX_DECLINED;
条件成立 name 的第一个字符是 /
被认为是 绝对路径
返回 NGX_OK
回到 ngx_get_full_name
rc = ngx_test_full_name(name);if (rc == NGX_OK) {return rc;}
rc 得到的返回值是 NGX_OK
条件成立,把这个 NGX_OK 返回到 ngx_conf_full_name
return ngx_get_full_name(cycle->pool, prefix, name);
这个结果继续向上返回到 ngx_process_options
回到 ngx_process_options
接下来是:
if (ngx_conf_full_name(cycle, &cycle->conf_file, 0) != NGX_OK) {return NGX_ERROR;}
于是 这里 调用 ngx_conf_full_name 得到 返回值 NGX_OK
条件不成立
接下来是:
for (p = cycle->conf_file.data + cycle->conf_file.len - 1;p > cycle->conf_file.data;p--){if (ngx_path_separator(*p)) {cycle->conf_prefix.len = p - cycle->conf_file.data + 1;cycle->conf_prefix.data = cycle->conf_file.data;break;}}
cycle->conf_file.data 是配置文件路径,
cycle->conf_file.data + cycle->conf_file.len - 1 指向这个路径字符串的最后一个字节
从最后一个字符向第一个字符遍历
if (ngx_path_separator(*p)) { 判断当前这个字符是否是分隔符 /
这个 分隔符后面是 配置文件的文件名,前面是配置文件的目录
将 cycle->conf_file.data 的地址赋给cycle->conf_prefix.data
从这个地址开始 len 个字符是 配置文件所在的目录
于是
cycle->conf_file.data(0x5bfbfeaf3e50) = cycle->conf_prefix.data(0x5bfbfeaf3e50)
这2个地址一样
cycle->conf_file.len=38
cycle->conf_file.data=/home/wsd/桌面/nginx/conf/nginx.conf
cycle->conf_prefix.len=28
cycle->conf_prefix.data=/home/wsd/桌面/nginx/conf/
就是 cycle->conf_file.data 的前 28 个字节
接下来是:
if (ngx_error_log) {cycle->error_log.len = ngx_strlen(ngx_error_log);cycle->error_log.data = ngx_error_log;} else {ngx_str_set(&cycle->error_log, NGX_ERROR_LOG_PATH);}
当前 ngx_error_log=null 还没有设置它
所以进入 else
把 默认值 NGX_ERROR_LOG_PATH(/home/wsd/桌面/nginx/LOG/error.log)
设置给 cycle->error_log
接下来是:
if (ngx_conf_params) {cycle->conf_param.len = ngx_strlen(ngx_conf_params);cycle->conf_param.data = ngx_conf_params;}
ngx_conf_params 没有设置是 null
所以跳过这段代码
if (ngx_test_config) {cycle->log->log_level = NGX_LOG_INFO;}
ngx_test_config 是 0
所以跳过这段代码
return NGX_OK;
返回结果
回到 main 函数中
接下来是:
if (ngx_os_init(log) != NGX_OK) {return 1;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_os_init 函数-CSDN博客
进入 ngx_os_init
ngx_int_t
ngx_os_init(ngx_log_t *log)
{ngx_time_t *tp;ngx_uint_t n;
#if (NGX_HAVE_LEVEL1_DCACHE_LINESIZE)long size;
#endif#if (NGX_HAVE_OS_SPECIFIC_INIT)if (ngx_os_specific_init(log) != NGX_OK) {return NGX_ERROR;}
#endif
调用 ngx_os_specific_init 函数
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_os_specific_init函数-CSDN博客
进入 ngx_os_specific_init
ngx_int_t
ngx_os_specific_init(ngx_log_t *log)
{struct utsname u;if (uname(&u) == -1) {ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "uname() failed");return NGX_ERROR;}
调用 uname 获取系统信息
这次获得的系统信息如下:
// 操作系统名称
u.sysname=Linux
//主机名
u.nodename=wsd-vm//操作系统发行版本
u.release=6.8.0-52-generic// 操作系统版本信息
u.version=#53~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Jan 15 19:18:46 UTC 2// 硬件架构
u.machine=x86_64
接下来是:
(void) ngx_cpystrn(ngx_linux_kern_ostype, (u_char *) u.sysname,sizeof(ngx_linux_kern_ostype));(void) ngx_cpystrn(ngx_linux_kern_osrelease, (u_char *) u.release,sizeof(ngx_linux_kern_osrelease));
复制 u.sysname 和 u.release 存储到全局变量 ngx_linux_kern_ostype 和 ngx_linux_kern_osrelease
ngx_os_io = ngx_linux_io;return NGX_OK;
设置 ngx_os_io
然后返回结果
回到 ngx_os_init
接下来是:
if (ngx_init_setproctitle(log) != NGX_OK) {return NGX_ERROR;}
调用 ngx_init_setproctitle
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_init_setproctitle函数-CSDN博客
进入 ngx_init_setproctitle
ngx_int_t
ngx_init_setproctitle(ngx_log_t *log)
{u_char *p;size_t size;ngx_uint_t i;size = 0;for (i = 0; environ[i]; i++) {size += ngx_strlen(environ[i]) + 1;}
遍历 环境变量
ngx_strlen(environ[i]) + 1;
是当前这个环境变量占用的内存字节数量(字符串长度 + 字符串结束标志 '\0')
累加到 size 中,最终 size 的值是整个环境变量占据的字节数量
这次的执行情况:
i=0
environ[0]="COLORTERM=truecolor"
ngx_strlen(environ[0]) + 1 =20
size=20i=1
environ[1]="LANGUAGE=zh_CN:en"
ngx_strlen(environ[1]) + 1 =18
size=38i=2
environ[2]="LC_ADDRESS=zh_CN.UTF-8"
ngx_strlen(environ[2]) + 1 =23
size=61i=3
environ[3]="LC_NAME=zh_CN.UTF-8"
ngx_strlen(environ[3]) + 1 =20
size=81i=4
environ[4]="LC_MONETARY=zh_CN.UTF-8"
ngx_strlen(environ[4]) + 1 =24
size=105i=5
environ[5]="XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.SUZ122"
ngx_strlen(environ[5]) + 1 =54
size=159i=6
environ[6]="LC_PAPER=zh_CN.UTF-8"
ngx_strlen(environ[6]) + 1 =21
size=180i=7
environ[7]="LANG=zh_CN.UTF-8"
ngx_strlen(environ[7]) + 1 =17
size=197i=8
environ[8]="LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:"
ngx_strlen(environ[8]) + 1 =1519
size=1716i=9
environ[9]="XDG_CURRENT_DESKTOP=ubuntu:GNOME"
ngx_strlen(environ[9]) + 1 =33
size=1749i=10
environ[10]="TERM=xterm-256color"
ngx_strlen(environ[10]) + 1 =20
size=1769i=11
environ[11]="LC_IDENTIFICATION=zh_CN.UTF-8"
ngx_strlen(environ[11]) + 1 =30
size=1799i=12
environ[12]="DISPLAY=:0"
ngx_strlen(environ[12]) + 1 =11
size=1810i=13
environ[13]="LC_TELEPHONE=zh_CN.UTF-8"
ngx_strlen(environ[13]) + 1 =25
size=1835i=14
environ[14]="LC_MEASUREMENT=zh_CN.UTF-8"
ngx_strlen(environ[14]) + 1 =27
size=1862i=15
environ[15]="LC_TIME=zh_CN.UTF-8"
ngx_strlen(environ[15]) + 1 =20
size=1882i=16
environ[16]="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
ngx_strlen(environ[16]) + 1 =76
size=1958i=17
environ[17]="LC_NUMERIC=zh_CN.UTF-8"
ngx_strlen(environ[17]) + 1 =23
size=1981i=18
environ[18]="MAIL=/var/mail/root"
ngx_strlen(environ[18]) + 1 =20
size=2001i=19
environ[19]="LOGNAME=root"
ngx_strlen(environ[19]) + 1 =13
size=2014i=20
environ[20]="USER=root"
ngx_strlen(environ[20]) + 1 =10
size=2024i=21
environ[21]="HOME=/root"
ngx_strlen(environ[21]) + 1 =11
size=2035i=22
environ[22]="SHELL=/bin/bash"
ngx_strlen(environ[22]) + 1 =16
size=2051i=23
environ[23]="SUDO_COMMAND=./nginx"
ngx_strlen(environ[23]) + 1 =21
size=2072i=24
environ[24]="SUDO_USER=wsd"
ngx_strlen(environ[24]) + 1 =14
size=2086i=25
environ[25]="SUDO_UID=1000"
ngx_strlen(environ[25]) + 1 =14
size=2100i=26
environ[26]="SUDO_GID=1000"
ngx_strlen(environ[26]) + 1 =14
size=2114
接下来是:
p = ngx_alloc(size, log);if (p == NULL) {return NGX_ERROR;}
为环境变量分配内存,环境变量将要迁移到新分配的内存中
此次运行的情况:
p = ngx_alloc(size=2114, log);
p=0x654273b10f20
接下来是:
ngx_os_argv_last = ngx_os_argv[0];
ngx_os_argv_last
将用于标记命令行参数可用的边界
ngx_os_argv[0]
是存储参数的那片内存的首地址
接下来是:
for (i = 0; ngx_os_argv[i]; i++) {if (ngx_os_argv_last == ngx_os_argv[i]) {ngx_os_argv_last = ngx_os_argv[i] + ngx_strlen(ngx_os_argv[i]) + 1;}}
循环,每次循环获取下一个参数的首地址,直到这个地址为 null,
null 是标记,意味着到此为止,后面没有更多的参数了
ngx_os_argv[i] 是参数首地址,ngx_strlen(ngx_os_argv[i]) 是参数的长度,最后再 + 1,就越过了这个参数的最后一个字节成了下一个参数的最后一个字节
所以下一次循环时 ngx_os_argv[i] 是下一个参数的首地址 等于 上一次循环被重新赋值的 ngx_os_argv_last
这样 ngx_os_argv_last
的值在不断的向后移动,直到它等于存贮参数的内存的最后一个字节的下一个字节(也是环境变量的第一个字节)
此次的执行情况是:
i=0
ngx_os_argv_last(0x7ffecc4747a6) == ngx_os_argv[0](0x7ffecc4747a6)
ngx_os_argv_last(0x7ffecc4747ae) = ngx_os_argv[0] + ngx_strlen(ngx_os_argv[0])(7) + 1;
因为此次运行时没有给命令行参数,所以 只有一个参数,也就是运行的程序名
接下来是:
for (i = 0; environ[i]; i++) {if (ngx_os_argv_last == environ[i]) {size = ngx_strlen(environ[i]) + 1;ngx_os_argv_last = environ[i] + size;ngx_cpystrn(p, (u_char *) environ[i], size);environ[i] = (char *) p;p += size;}}
现在 ngx_os_argv_last
等于环境变量的首地址
循环逻辑与上一个循环相同
ngx_os_argv_last
逐渐向后移
每次遍历还会将 环境变量依次迁移到新分配的内存
此次的运行情况:
i=0
ngx_os_argv_last(=0x7ffde3e967ae) == environ[0](=0x7ffde3e967ae)
size(=20) = ngx_strlen(environ[0])(=19) + 1;
ngx_os_argv_last(=0x7ffde3e967c2) = environ[0](=0x7ffde3e967ae) + size(=20);
ngx_cpystrn(0x62a807451f20, 0x7ffde3e967ae, 20);
environ[0](=0x62a807451f20) = (char *) p(=0x62a807451f20);
p(=0x62a807451f34) += size(=20);i=1
ngx_os_argv_last(=0x7ffde3e967c2) == environ[1](=0x7ffde3e967c2)
size(=18) = ngx_strlen(environ[1])(=17) + 1;
ngx_os_argv_last(=0x7ffde3e967d4) = environ[1](=0x7ffde3e967c2) + size(=18);
ngx_cpystrn(0x62a807451f34, 0x7ffde3e967c2, 18);
environ[1](=0x62a807451f34) = (char *) p(=0x62a807451f34);
p(=0x62a807451f46) += size(=18);i=2
ngx_os_argv_last(=0x7ffde3e967d4) == environ[2](=0x7ffde3e967d4)
size(=23) = ngx_strlen(environ[2])(=22) + 1;
ngx_os_argv_last(=0x7ffde3e967eb) = environ[2](=0x7ffde3e967d4) + size(=23);
ngx_cpystrn(0x62a807451f46, 0x7ffde3e967d4, 23);
environ[2](=0x62a807451f46) = (char *) p(=0x62a807451f46);
p(=0x62a807451f5d) += size(=23);i=3
ngx_os_argv_last(=0x7ffde3e967eb) == environ[3](=0x7ffde3e967eb)
size(=20) = ngx_strlen(environ[3])(=19) + 1;
ngx_os_argv_last(=0x7ffde3e967ff) = environ[3](=0x7ffde3e967eb) + size(=20);
ngx_cpystrn(0x62a807451f5d, 0x7ffde3e967eb, 20);
environ[3](=0x62a807451f5d) = (char *) p(=0x62a807451f5d);
p(=0x62a807451f71) += size(=20);i=4
ngx_os_argv_last(=0x7ffde3e967ff) == environ[4](=0x7ffde3e967ff)
size(=24) = ngx_strlen(environ[4])(=23) + 1;
ngx_os_argv_last(=0x7ffde3e96817) = environ[4](=0x7ffde3e967ff) + size(=24);
ngx_cpystrn(0x62a807451f71, 0x7ffde3e967ff, 24);
environ[4](=0x62a807451f71) = (char *) p(=0x62a807451f71);
p(=0x62a807451f89) += size(=24);i=5
ngx_os_argv_last(=0x7ffde3e96817) == environ[5](=0x7ffde3e96817)
size(=54) = ngx_strlen(environ[5])(=53) + 1;
ngx_os_argv_last(=0x7ffde3e9684d) = environ[5](=0x7ffde3e96817) + size(=54);
ngx_cpystrn(0x62a807451f89, 0x7ffde3e96817, 54);
environ[5](=0x62a807451f89) = (char *) p(=0x62a807451f89);
p(=0x62a807451fbf) += size(=54);i=6
ngx_os_argv_last(=0x7ffde3e9684d) == environ[6](=0x7ffde3e9684d)
size(=21) = ngx_strlen(environ[6])(=20) + 1;
ngx_os_argv_last(=0x7ffde3e96862) = environ[6](=0x7ffde3e9684d) + size(=21);
ngx_cpystrn(0x62a807451fbf, 0x7ffde3e9684d, 21);
environ[6](=0x62a807451fbf) = (char *) p(=0x62a807451fbf);
p(=0x62a807451fd4) += size(=21);i=7
ngx_os_argv_last(=0x7ffde3e96862) == environ[7](=0x7ffde3e96862)
size(=17) = ngx_strlen(environ[7])(=16) + 1;
ngx_os_argv_last(=0x7ffde3e96873) = environ[7](=0x7ffde3e96862) + size(=17);
ngx_cpystrn(0x62a807451fd4, 0x7ffde3e96862, 17);
environ[7](=0x62a807451fd4) = (char *) p(=0x62a807451fd4);
p(=0x62a807451fe5) += size(=17);i=8
ngx_os_argv_last(=0x7ffde3e96873) == environ[8](=0x7ffde3e96873)
size(=1519) = ngx_strlen(environ[8])(=1518) + 1;
ngx_os_argv_last(=0x7ffde3e96e62) = environ[8](=0x7ffde3e96873) + size(=1519);
ngx_cpystrn(0x62a807451fe5, 0x7ffde3e96873, 1519);
environ[8](=0x62a807451fe5) = (char *) p(=0x62a807451fe5);
p(=0x62a8074525d4) += size(=1519);i=9
ngx_os_argv_last(=0x7ffde3e96e62) == environ[9](=0x7ffde3e96e62)
size(=33) = ngx_strlen(environ[9])(=32) + 1;
ngx_os_argv_last(=0x7ffde3e96e83) = environ[9](=0x7ffde3e96e62) + size(=33);
ngx_cpystrn(0x62a8074525d4, 0x7ffde3e96e62, 33);
environ[9](=0x62a8074525d4) = (char *) p(=0x62a8074525d4);
p(=0x62a8074525f5) += size(=33);i=10
ngx_os_argv_last(=0x7ffde3e96e83) == environ[10](=0x7ffde3e96e83)
size(=20) = ngx_strlen(environ[10])(=19) + 1;
ngx_os_argv_last(=0x7ffde3e96e97) = environ[10](=0x7ffde3e96e83) + size(=20);
ngx_cpystrn(0x62a8074525f5, 0x7ffde3e96e83, 20);
environ[10](=0x62a8074525f5) = (char *) p(=0x62a8074525f5);
p(=0x62a807452609) += size(=20);i=11
ngx_os_argv_last(=0x7ffde3e96e97) == environ[11](=0x7ffde3e96e97)
size(=30) = ngx_strlen(environ[11])(=29) + 1;
ngx_os_argv_last(=0x7ffde3e96eb5) = environ[11](=0x7ffde3e96e97) + size(=30);
ngx_cpystrn(0x62a807452609, 0x7ffde3e96e97, 30);
environ[11](=0x62a807452609) = (char *) p(=0x62a807452609);
p(=0x62a807452627) += size(=30);i=12
ngx_os_argv_last(=0x7ffde3e96eb5) == environ[12](=0x7ffde3e96eb5)
size(=11) = ngx_strlen(environ[12])(=10) + 1;
ngx_os_argv_last(=0x7ffde3e96ec0) = environ[12](=0x7ffde3e96eb5) + size(=11);
ngx_cpystrn(0x62a807452627, 0x7ffde3e96eb5, 11);
environ[12](=0x62a807452627) = (char *) p(=0x62a807452627);
p(=0x62a807452632) += size(=11);i=13
ngx_os_argv_last(=0x7ffde3e96ec0) == environ[13](=0x7ffde3e96ec0)
size(=25) = ngx_strlen(environ[13])(=24) + 1;
ngx_os_argv_last(=0x7ffde3e96ed9) = environ[13](=0x7ffde3e96ec0) + size(=25);
ngx_cpystrn(0x62a807452632, 0x7ffde3e96ec0, 25);
environ[13](=0x62a807452632) = (char *) p(=0x62a807452632);
p(=0x62a80745264b) += size(=25);i=14
ngx_os_argv_last(=0x7ffde3e96ed9) == environ[14](=0x7ffde3e96ed9)
size(=27) = ngx_strlen(environ[14])(=26) + 1;
ngx_os_argv_last(=0x7ffde3e96ef4) = environ[14](=0x7ffde3e96ed9) + size(=27);
ngx_cpystrn(0x62a80745264b, 0x7ffde3e96ed9, 27);
environ[14](=0x62a80745264b) = (char *) p(=0x62a80745264b);
p(=0x62a807452666) += size(=27);i=15
ngx_os_argv_last(=0x7ffde3e96ef4) == environ[15](=0x7ffde3e96ef4)
size(=20) = ngx_strlen(environ[15])(=19) + 1;
ngx_os_argv_last(=0x7ffde3e96f08) = environ[15](=0x7ffde3e96ef4) + size(=20);
ngx_cpystrn(0x62a807452666, 0x7ffde3e96ef4, 20);
environ[15](=0x62a807452666) = (char *) p(=0x62a807452666);
p(=0x62a80745267a) += size(=20);i=16
ngx_os_argv_last(=0x7ffde3e96f08) == environ[16](=0x7ffde3e96f08)
size(=76) = ngx_strlen(environ[16])(=75) + 1;
ngx_os_argv_last(=0x7ffde3e96f54) = environ[16](=0x7ffde3e96f08) + size(=76);
ngx_cpystrn(0x62a80745267a, 0x7ffde3e96f08, 76);
environ[16](=0x62a80745267a) = (char *) p(=0x62a80745267a);
p(=0x62a8074526c6) += size(=76);i=17
ngx_os_argv_last(=0x7ffde3e96f54) == environ[17](=0x7ffde3e96f54)
size(=23) = ngx_strlen(environ[17])(=22) + 1;
ngx_os_argv_last(=0x7ffde3e96f6b) = environ[17](=0x7ffde3e96f54) + size(=23);
ngx_cpystrn(0x62a8074526c6, 0x7ffde3e96f54, 23);
environ[17](=0x62a8074526c6) = (char *) p(=0x62a8074526c6);
p(=0x62a8074526dd) += size(=23);i=18
ngx_os_argv_last(=0x7ffde3e96f6b) == environ[18](=0x7ffde3e96f6b)
size(=20) = ngx_strlen(environ[18])(=19) + 1;
ngx_os_argv_last(=0x7ffde3e96f7f) = environ[18](=0x7ffde3e96f6b) + size(=20);
ngx_cpystrn(0x62a8074526dd, 0x7ffde3e96f6b, 20);
environ[18](=0x62a8074526dd) = (char *) p(=0x62a8074526dd);
p(=0x62a8074526f1) += size(=20);i=19
ngx_os_argv_last(=0x7ffde3e96f7f) == environ[19](=0x7ffde3e96f7f)
size(=13) = ngx_strlen(environ[19])(=12) + 1;
ngx_os_argv_last(=0x7ffde3e96f8c) = environ[19](=0x7ffde3e96f7f) + size(=13);
ngx_cpystrn(0x62a8074526f1, 0x7ffde3e96f7f, 13);
environ[19](=0x62a8074526f1) = (char *) p(=0x62a8074526f1);
p(=0x62a8074526fe) += size(=13);i=20
ngx_os_argv_last(=0x7ffde3e96f8c) == environ[20](=0x7ffde3e96f8c)
size(=10) = ngx_strlen(environ[20])(=9) + 1;
ngx_os_argv_last(=0x7ffde3e96f96) = environ[20](=0x7ffde3e96f8c) + size(=10);
ngx_cpystrn(0x62a8074526fe, 0x7ffde3e96f8c, 10);
environ[20](=0x62a8074526fe) = (char *) p(=0x62a8074526fe);
p(=0x62a807452708) += size(=10);i=21
ngx_os_argv_last(=0x7ffde3e96f96) == environ[21](=0x7ffde3e96f96)
size(=11) = ngx_strlen(environ[21])(=10) + 1;
ngx_os_argv_last(=0x7ffde3e96fa1) = environ[21](=0x7ffde3e96f96) + size(=11);
ngx_cpystrn(0x62a807452708, 0x7ffde3e96f96, 11);
environ[21](=0x62a807452708) = (char *) p(=0x62a807452708);
p(=0x62a807452713) += size(=11);i=22
ngx_os_argv_last(=0x7ffde3e96fa1) == environ[22](=0x7ffde3e96fa1)
size(=16) = ngx_strlen(environ[22])(=15) + 1;
ngx_os_argv_last(=0x7ffde3e96fb1) = environ[22](=0x7ffde3e96fa1) + size(=16);
ngx_cpystrn(0x62a807452713, 0x7ffde3e96fa1, 16);
environ[22](=0x62a807452713) = (char *) p(=0x62a807452713);
p(=0x62a807452723) += size(=16);i=23
ngx_os_argv_last(=0x7ffde3e96fb1) == environ[23](=0x7ffde3e96fb1)
size(=21) = ngx_strlen(environ[23])(=20) + 1;
ngx_os_argv_last(=0x7ffde3e96fc6) = environ[23](=0x7ffde3e96fb1) + size(=21);
ngx_cpystrn(0x62a807452723, 0x7ffde3e96fb1, 21);
environ[23](=0x62a807452723) = (char *) p(=0x62a807452723);
p(=0x62a807452738) += size(=21);i=24
ngx_os_argv_last(=0x7ffde3e96fc6) == environ[24](=0x7ffde3e96fc6)
size(=14) = ngx_strlen(environ[24])(=13) + 1;
ngx_os_argv_last(=0x7ffde3e96fd4) = environ[24](=0x7ffde3e96fc6) + size(=14);
ngx_cpystrn(0x62a807452738, 0x7ffde3e96fc6, 14);
environ[24](=0x62a807452738) = (char *) p(=0x62a807452738);
p(=0x62a807452746) += size(=14);i=25
ngx_os_argv_last(=0x7ffde3e96fd4) == environ[25](=0x7ffde3e96fd4)
size(=14) = ngx_strlen(environ[25])(=13) + 1;
ngx_os_argv_last(=0x7ffde3e96fe2) = environ[25](=0x7ffde3e96fd4) + size(=14);
ngx_cpystrn(0x62a807452746, 0x7ffde3e96fd4, 14);
environ[25](=0x62a807452746) = (char *) p(=0x62a807452746);
p(=0x62a807452754) += size(=14);i=26
ngx_os_argv_last(=0x7ffde3e96fe2) == environ[26](=0x7ffde3e96fe2)
size(=14) = ngx_strlen(environ[26])(=13) + 1;
ngx_os_argv_last(=0x7ffde3e96ff0) = environ[26](=0x7ffde3e96fe2) + size(=14);
ngx_cpystrn(0x62a807452754, 0x7ffde3e96fe2, 14);
environ[26](=0x62a807452754) = (char *) p(=0x62a807452754);
p(=0x62a807452762) += size(=14);
接下来是:
ngx_os_argv_last--;return NGX_OK;
ngx_os_argv_last 的值 -1,指向原来存放环境变量的那片内存的最后一个字节
然后返回
回到 ngx_os_init
接下来是:
ngx_pagesize = getpagesize();
获取 当前系统一页的大小是多少字节
此次的情况
ngx_pagesize=4096
ngx_cacheline_size = NGX_CPU_CACHE_LINE;
存储 CPU 缓存行大小,默认值为 NGX_CPU_CACHE_LINE
目前的情况:
ngx_cacheline_size=64
for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }
计算页面大小的对数(ngx_pagesize_shift
),即页面大小是 2 的多少次幂。
例如,4KB 的页面大小对应 ngx_pagesize_shift = 12
此次的情况:
ngx_pagesize_shift=12
if (ngx_ncpu == 0) {ngx_ncpu = sysconf(_SC_NPROCESSORS_ONLN);}
获取当前系统在线的 CPU 核心数
此次的情况是:
ngx_ncpu=2
if (ngx_ncpu < 1) {ngx_ncpu = 1;}
条件不成立,跳过这段代码
size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);if (size > 0) {ngx_cacheline_size = size;}
sysconf(_SC_LEVEL1_DCACHE_LINESIZE)
:获取一级缓存行大小
成功就更新 ngx_cacheline_size ,之前的值是默认值
此次的情况:
获取成功,但获得的值和默认值一样
ngx_cacheline_size=64
接下来是:
ngx_cpuinfo();
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_cpuinfo 函数-CSDN博客
接下来是:
if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {ngx_log_error(NGX_LOG_ALERT, log, errno,"getrlimit(RLIMIT_NOFILE) failed");return NGX_ERROR;}ngx_max_sockets = (ngx_int_t) rlmt.rlim_cur;
获取文件描述符数量的限制
此次的情况是:
ngx_max_sockets=1024
#if (NGX_HAVE_INHERITED_NONBLOCK || NGX_HAVE_ACCEPT4)ngx_inherited_nonblocking = 1;
#elsengx_inherited_nonblocking = 0;
#endif
ngx_inherited_nonblocking
:全局变量,指示当前环境是否支持继承非阻塞套接字
当前情况:
ngx_inherited_nonblocking=1
tp = ngx_timeofday();srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec);return NGX_OK;
获取当前的时间缓存 用来 设置随机数种子
返回 NGX_OK
回到 main 函数中
接下来是:
if (ngx_crc32_table_init() != NGX_OK) {return 1;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_crc32_table_init 函数-CSDN博客
ngx_slab_sizes_init();
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_slab_sizes_init 函数-CSDN博客
进入 ngx_slab_sizes_init
void
ngx_slab_sizes_init(void)
{ngx_uint_t n;ngx_slab_max_size = ngx_pagesize / 2;ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t));for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) {/* void */}
}
此次的情况是:
ngx_slab_max_size=2048
ngx_slab_exact_size=64
ngx_slab_exact_shift=6
回到 main 函数中
接下来是:
if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {return 1;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_add_inherited_sockets函数-CSDN博客
进入 ngx_add_inherited_sockets
static ngx_int_t
ngx_add_inherited_sockets(ngx_cycle_t *cycle)
{u_char *p, *v, *inherited;ngx_int_t s;ngx_listening_t *ls;inherited = (u_char *) getenv(NGINX_VAR);
此次
inherited 是 null,没有需要继承的 套接字描述符
if (inherited == NULL) {return NGX_OK;}
返回 NGX_OK
回到 main 函数中
接下来是:
if (ngx_preinit_modules() != NGX_OK) {return 1;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_preinit_modules 函数-CSDN博客
进入 ngx_preinit_modules
ngx_int_t
ngx_preinit_modules(void)
{ngx_uint_t i;for (i = 0; ngx_modules[i]; i++) {ngx_modules[i]->index = i;ngx_modules[i]->name = ngx_module_names[i];}ngx_modules_n = i;ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;return NGX_OK;
}
进入循环,遍历 ngx_modules 数组
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_modules-CSDN博客
为每个模块的 index 和 name 字段赋值
此次的情况是:
ngx_modules[0]->index = 0
ngx_modules[0]->name = ngx_core_module
ngx_modules[1]->index = 1
ngx_modules[1]->name = ngx_errlog_module
ngx_modules[2]->index = 2
ngx_modules[2]->name = ngx_conf_module
ngx_modules[3]->index = 3
ngx_modules[3]->name = ngx_openssl_module
ngx_modules[4]->index = 4
ngx_modules[4]->name = ngx_regex_module
ngx_modules[5]->index = 5
ngx_modules[5]->name = ngx_events_module
ngx_modules[6]->index = 6
ngx_modules[6]->name = ngx_event_core_module
ngx_modules[7]->index = 7
ngx_modules[7]->name = ngx_epoll_module
ngx_modules[8]->index = 8
ngx_modules[8]->name = ngx_http_module
ngx_modules[9]->index = 9
ngx_modules[9]->name = ngx_http_core_module
ngx_modules[10]->index = 10
ngx_modules[10]->name = ngx_http_log_module
ngx_modules[11]->index = 11
ngx_modules[11]->name = ngx_http_upstream_module
ngx_modules[12]->index = 12
ngx_modules[12]->name = ngx_http_v2_module
ngx_modules[13]->index = 13
ngx_modules[13]->name = ngx_http_static_module
ngx_modules[14]->index = 14
ngx_modules[14]->name = ngx_http_gzip_static_module
ngx_modules[15]->index = 15
ngx_modules[15]->name = ngx_http_autoindex_module
ngx_modules[16]->index = 16
ngx_modules[16]->name = ngx_http_index_module
ngx_modules[17]->index = 17
ngx_modules[17]->name = ngx_http_mirror_module
ngx_modules[18]->index = 18
ngx_modules[18]->name = ngx_http_try_files_module
ngx_modules[19]->index = 19
ngx_modules[19]->name = ngx_http_auth_basic_module
ngx_modules[20]->index = 20
ngx_modules[20]->name = ngx_http_access_module
ngx_modules[21]->index = 21
ngx_modules[21]->name = ngx_http_limit_conn_module
ngx_modules[22]->index = 22
ngx_modules[22]->name = ngx_http_limit_req_module
ngx_modules[23]->index = 23
ngx_modules[23]->name = ngx_http_geo_module
ngx_modules[24]->index = 24
ngx_modules[24]->name = ngx_http_map_module
ngx_modules[25]->index = 25
ngx_modules[25]->name = ngx_http_split_clients_module
ngx_modules[26]->index = 26
ngx_modules[26]->name = ngx_http_referer_module
ngx_modules[27]->index = 27
ngx_modules[27]->name = ngx_http_rewrite_module
ngx_modules[28]->index = 28
ngx_modules[28]->name = ngx_http_ssl_module
ngx_modules[29]->index = 29
ngx_modules[29]->name = ngx_http_proxy_module
ngx_modules[30]->index = 30
ngx_modules[30]->name = ngx_http_fastcgi_module
ngx_modules[31]->index = 31
ngx_modules[31]->name = ngx_http_uwsgi_module
ngx_modules[32]->index = 32
ngx_modules[32]->name = ngx_http_scgi_module
ngx_modules[33]->index = 33
ngx_modules[33]->name = ngx_http_grpc_module
ngx_modules[34]->index = 34
ngx_modules[34]->name = ngx_http_memcached_module
ngx_modules[35]->index = 35
ngx_modules[35]->name = ngx_http_empty_gif_module
ngx_modules[36]->index = 36
ngx_modules[36]->name = ngx_http_browser_module
ngx_modules[37]->index = 37
ngx_modules[37]->name = ngx_http_upstream_hash_module
ngx_modules[38]->index = 38
ngx_modules[38]->name = ngx_http_upstream_ip_hash_module
ngx_modules[39]->index = 39
ngx_modules[39]->name = ngx_http_upstream_least_conn_module
ngx_modules[40]->index = 40
ngx_modules[40]->name = ngx_http_upstream_random_module
ngx_modules[41]->index = 41
ngx_modules[41]->name = ngx_http_upstream_keepalive_module
ngx_modules[42]->index = 42
ngx_modules[42]->name = ngx_http_upstream_zone_module
ngx_modules[43]->index = 43
ngx_modules[43]->name = ngx_http_write_filter_module
ngx_modules[44]->index = 44
ngx_modules[44]->name = ngx_http_header_filter_module
ngx_modules[45]->index = 45
ngx_modules[45]->name = ngx_http_chunked_filter_module
ngx_modules[46]->index = 46
ngx_modules[46]->name = ngx_http_v2_filter_module
ngx_modules[47]->index = 47
ngx_modules[47]->name = ngx_http_range_header_filter_module
ngx_modules[48]->index = 48
ngx_modules[48]->name = ngx_http_gzip_filter_module
ngx_modules[49]->index = 49
ngx_modules[49]->name = ngx_http_postpone_filter_module
ngx_modules[50]->index = 50
ngx_modules[50]->name = ngx_http_ssi_filter_module
ngx_modules[51]->index = 51
ngx_modules[51]->name = ngx_http_charset_filter_module
ngx_modules[52]->index = 52
ngx_modules[52]->name = ngx_http_userid_filter_module
ngx_modules[53]->index = 53
ngx_modules[53]->name = ngx_http_headers_filter_module
ngx_modules[54]->index = 54
ngx_modules[54]->name = ngx_http_copy_filter_module
ngx_modules[55]->index = 55
ngx_modules[55]->name = ngx_http_range_body_filter_module
ngx_modules[56]->index = 56
ngx_modules[56]->name = ngx_http_not_modified_filter_module
ngx_modules[57]->index = 57
ngx_modules[57]->name = ngx_stream_module
ngx_modules[58]->index = 58
ngx_modules[58]->name = ngx_stream_core_module
ngx_modules[59]->index = 59
ngx_modules[59]->name = ngx_stream_log_module
ngx_modules[60]->index = 60
ngx_modules[60]->name = ngx_stream_proxy_module
ngx_modules[61]->index = 61
ngx_modules[61]->name = ngx_stream_upstream_module
ngx_modules[62]->index = 62
ngx_modules[62]->name = ngx_stream_write_filter_module
ngx_modules[63]->index = 63
ngx_modules[63]->name = ngx_stream_ssl_module
ngx_modules[64]->index = 64
ngx_modules[64]->name = ngx_stream_limit_conn_module
ngx_modules[65]->index = 65
ngx_modules[65]->name = ngx_stream_access_module
ngx_modules[66]->index = 66
ngx_modules[66]->name = ngx_stream_geo_module
ngx_modules[67]->index = 67
ngx_modules[67]->name = ngx_stream_map_module
ngx_modules[68]->index = 68
ngx_modules[68]->name = ngx_stream_split_clients_module
ngx_modules[69]->index = 69
ngx_modules[69]->name = ngx_stream_return_module
ngx_modules[70]->index = 70
ngx_modules[70]->name = ngx_stream_set_module
ngx_modules[71]->index = 71
ngx_modules[71]->name = ngx_stream_upstream_hash_module
ngx_modules[72]->index = 72
ngx_modules[72]->name = ngx_stream_upstream_least_conn_module
ngx_modules[73]->index = 73
ngx_modules[73]->name = ngx_stream_upstream_random_module
ngx_modules[74]->index = 74
ngx_modules[74]->name = ngx_stream_upstream_zone_module
ngx_modules_n 静态模块的总数
ngx_max_module 表示Nginx支持的最大模块数量
NGX_MAX_DYNAMIC_MODULES 动态加载模块的最大数量
ngx_modules_n=75
ngx_max_module(=203) = ngx_modules_n(75) + NGX_MAX_DYNAMIC_MODULES(128)
回到 main 函数中
接下来是:
cycle = ngx_init_cycle(&init_cycle);if (cycle == NULL) {if (ngx_test_config) {ngx_log_stderr(0, "configuration file %s test failed",init_cycle.conf_file.data);}return 1;}
调用 ngx_init_cycle
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_init_cycle 函数-CSDN博客
进入 ngx_init_cycle
ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{void *rv;char **senv;ngx_uint_t i, n;ngx_log_t *log;ngx_time_t *tp;ngx_conf_t conf;ngx_pool_t *pool;ngx_cycle_t *cycle, **old;ngx_shm_zone_t *shm_zone, *oshm_zone;ngx_list_part_t *part, *opart;ngx_open_file_t *file;ngx_listening_t *ls, *nls;ngx_core_conf_t *ccf, *old_ccf;ngx_core_module_t *module;char hostname[NGX_MAXHOSTNAMELEN];ngx_timezone_update();/* force localtime update with a new timezone */tp = ngx_timeofday();tp->sec = 0;ngx_time_update();
更新时间
log = old_cycle->log;
获取之前的 log 对象,暂时还是用它来记录 log
pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);if (pool == NULL) {return NULL;}pool->log = log;
创建一个新的内存池,然后设置它使用的 log
此次的情况是:
pool = ngx_create_pool(16384, log)
pool= 0x5f33e4db67b0 (地址)
接下来是:
cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));if (cycle == NULL) {ngx_destroy_pool(pool);return NULL;}
此次的情况是:
cycle = ngx_pcalloc(pool, 648);
cycle= 0x5c67408e7800
cycle->pool = pool;cycle->log = log;cycle->old_cycle = old_cycle;
cycle->conf_prefix.len = old_cycle->conf_prefix.len;cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);if (cycle->conf_prefix.data == NULL) {ngx_destroy_pool(pool);return NULL;}
给字段赋值
此次的情况是:
cycle->conf_prefix.len =28
cycle->conf_prefix.data=/home/wsd/桌面/nginx/conf/
cycle->prefix.len = old_cycle->prefix.len;cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);if (cycle->prefix.data == NULL) {ngx_destroy_pool(pool);return NULL;}
此次的情况是:
cycle->prefix.len = 17)
cycle->prefix.data= /usr/local/nginx/
cycle->error_log.len = old_cycle->error_log.len;cycle->error_log.data = ngx_pnalloc(pool, old_cycle->error_log.len + 1);if (cycle->error_log.data == NULL) {ngx_destroy_pool(pool);return NULL;}ngx_cpystrn(cycle->error_log.data, old_cycle->error_log.data,old_cycle->error_log.len + 1);
此次的情况是:
cycle->error_log.len=36
cycle->error_log.data=/home/wsd/桌面/nginx/LOG/error.log
cycle->conf_file.len = old_cycle->conf_file.len;cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);if (cycle->conf_file.data == NULL) {ngx_destroy_pool(pool);return NULL;}ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,old_cycle->conf_file.len + 1);
此次的情况是:
cycle->conf_file.len=38
cycle->conf_file.data=/home/wsd/桌面/nginx/conf/nginx.conf
cycle->conf_param.len = old_cycle->conf_param.len;cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);if (cycle->conf_param.data == NULL) {ngx_destroy_pool(pool);return NULL;}
此次的情况是:
cycle->conf_param.len=0
cycle->conf_param.data 是 null运行时没有给命令行参数
n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
此次的情况是:
n = 0 ? 0 : 10;
n=10
if (ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_array_init 函数-CSDN博客
ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *));
将 paths
数组的前 n
个元素清零
if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}
初始化数组 config_dump
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_conf_dump_t-CSDN博客
ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel,ngx_str_rbtree_insert_value);
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_rbtree_init-CSDN博客
if (old_cycle->open_files.part.nelts) {n = old_cycle->open_files.part.nelts;for (part = old_cycle->open_files.part.next; part; part = part->next) {n += part->nelts;}} else {n = 20;}
此次运行的情况是:
old_cycle->open_files.part.nelts=0
所以进入 else
n=20
if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}
初始化新周期的 open_files
列表。
此次运行的情况是:
ngx_list_init(&cycle->open_files, pool, n=20, sizeof(ngx_open_file_t)=40)
if (old_cycle->shared_memory.part.nelts) {n = old_cycle->shared_memory.part.nelts;for (part = old_cycle->shared_memory.part.next; part; part = part->next){n += part->nelts;}} else {n = 1;}
设置新周期的 shared_memory 的元素数量
此次运行的情况是:
old_cycle->shared_memory.part.nelts=0
所以 进入else
n=1
if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}
初始化 shared_memory
此次运行的情况是:
ngx_list_init(&cycle->shared_memory, pool, n=1, sizeof(ngx_shm_zone_t)=88 )
n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
此次运行的情况是:
n(=10) = old_cycle->listening.nelts(=0) ? old_cycle->listening.nelts(=0) : 10
if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}
初始化 cycle->listening
数组
此次运行的情况是:
ngx_array_init(&cycle->listening, pool, n(=10), sizeof(ngx_listening_t)(=296))
ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));
将 cycle->listening
的
内存区域清 0
ngx_queue_init(&cycle->reusable_connections_queue);
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));if (cycle->conf_ctx == NULL) {ngx_destroy_pool(pool);return NULL;}
从内存池 pool 中分配一个指针数组 conf_ctx,每个元素对应一个模块的配置结构指针。
if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");ngx_destroy_pool(pool);return NULL;}
调用 gethostname()
系统调用获取本地主机名,存储到 hostname
缓冲区。
hostname[NGX_MAXHOSTNAMELEN - 1] = '\0';cycle->hostname.len = ngx_strlen(hostname);
确保 hostname
以 \0
结尾
计算主机名的实际长度(不含终止符),存储到 cycle->hostname.len
cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len);if (cycle->hostname.data == NULL) {ngx_destroy_pool(pool);return NULL;}
从内存池 pool
分配内存,存储主机名的副本
ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
将主机名转换为全小写,存储到 cycle->hostname.data
此次运行的情况是:
hostname=wsd-vm
cycle->hostname.len=6
cycle->hostname.data = ngx_pnalloc(pool, 6)
cycle->hostname.data=0x6165d5b590d0 地址
cycle->hostname.data = wsd-vm
if (ngx_cycle_modules(cycle) != NGX_OK) {ngx_destroy_pool(pool);return NULL;}
调用 ngx_cycle_modules 初始化 cycle->modules 数组,该数组包含所有核心模块的指针
for (i = 0; cycle->modules[i]; i++) {if (cycle->modules[i]->type != NGX_CORE_MODULE) {continue;}
遍历所有核心模块
module = cycle->modules[i]->ctx;
相关文章:
Ubuntu 下 nginx-1.24.0 源码分析 (1)
main 函数在 src\core\nginx.c int ngx_cdecl main(int argc, char *const *argv) {ngx_buf_t *b;ngx_log_t *log;ngx_uint_t i;ngx_cycle_t *cycle, init_cycle;ngx_conf_dump_t *cd;ngx_core_conf_t *ccf;ngx_debug_init(); 进入 main 函数 最…...
驱动开发系列43 - Linux 显卡KMD驱动代码分析(四)- DRM设备操作
一:概述 DRM(Direct Rendering Manager)是Linux内核中的一个子系统,主要负责图形硬件的管理与图形渲染的加速。它为图形驱动提供了一个统一的接口,可以使用户空间程序与图形硬件进行直接交互,而无需通过X服务器或Wayland等显示管理器。DRM不仅用于管理显卡,还处理视频输…...
PAT乙级真题(2014·冬)
大纲 1031、查验身份证-(解析)-简单题 1032、挖掘机技术哪家强-(解析)-细节题(┬┬﹏┬┬),太抠细节了 1033、旧键盘打字-(解析)-输入格式!这才是重点(┬┬﹏┬┬),让…...
快速使用MASR V3版不能语音识别框架
前言 本文章主要介绍如何快速使用MASR语音识别框架训练和推理,本文将致力于最简单的方式去介绍使用,如果使用更进阶功能,还需要从源码去看文档。仅需三行代码即可实现训练和推理。 源码地址:https://github.com/yeyupiaoling/MA…...
学习笔记:Python网络编程初探之基本概念(一)
一、网络目的 让你设备上的数据和其他设备上进行共享,使用网络能够把多方链接在一起,然后可以进行数据传递。 网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信。 二、IP地址的作用 用来标记唯一一台电脑…...
硬件基础(4):(2)认识ADC参考电压
文章目录 1. **ADC参考电压的定义**2. **如何影响采样值**3. **参考电压的选择**4. **如何选择参考电压**5. **总结** **ADC参考电压(Vref)**是用于定义ADC采样范围的一个重要参数,以下是对 ADC 参考电压的详细解释: 1. ADC参考电…...
项目中同时使用Redis(lettuce)和Redisson的报错
温馨提示:图片有点小,可以放大页面进行查看... 问题1:版本冲突 直接上图,这个错表示依赖版本不匹配问题,我本地SpringBoot用的是2.7,但是Redisson版本用的3.32.5。 我们通过点击 artifactId跟进去 发现它…...
工程化与框架系列(25)--低代码平台开发
低代码平台开发 🔧 引言 低代码开发平台是一种通过可视化配置和少量代码实现应用开发的技术方案。本文将深入探讨低代码平台的设计与实现,包括可视化编辑器、组件系统、数据流管理等关键主题,帮助开发者构建高效的低代码开发平台。 低代码…...
在CentOS系统上安装Conda的详细指南
前言 Conda 是一个开源的包管理系统和环境管理系统,广泛应用于数据科学和机器学习领域。本文将详细介绍如何在 CentOS 系统上安装 Conda,帮助您快速搭建开发环境。 准备工作 在开始安装之前,请确保您的 CentOS 系统已经满足以下条件&#x…...
系统思考—组织诊断
“未经过诊断的行动是盲目的。” — 托马斯爱迪生 最近和一家教育培训机构沟通时,发现他们面临一个有意思的问题:每年招生都挺不错,但教师的整体绩效一直提升缓慢,导致师生之间存在长期的不匹配。管理层试了很多办法,…...
项目实战--网页五子棋(对战功能)(9)
上期我们完成了websocket建立连接后的数据初始化,今天我们完成落子交互的具体代码: 这里我们先复习一下,之前约定好的落子请求与响应包含的字段: 1. 发送落子请求 我们在script.js文件中找到落子的相关方法,增加发送请…...
Ubuntu系统安装Apache2方法
Ubuntu系统安装Apache2方法 一、安装 Apache2更新软件包列表安装 Apache2启动服务验证安装 二、访问默认页面三、基本配置配置文件结构目录权限访问测试 四、故障排除五、总结 一、安装 Apache2 更新软件包列表 在安装任何软件之前,建议先更新系统的软件包列表&am…...
DeepSeek R1-32B医疗大模型的完整微调实战分析(全码版)
DeepSeek R1-32B微调实战指南 ├── 1. 环境准备 │ ├── 1.1 硬件配置 │ │ ├─ 全参数微调:4*A100 80GB │ │ └─ LoRA微调:单卡24GB │ ├── 1.2 软件依赖 │ │ ├─ PyTorch 2.1.2+CUDA │ │ └─ Unsloth/ColossalAI │ └── 1.3 模…...
基于springboot和spring-boot-starter-data-jpa快速操作mysql数据库
1、创建springboot项目 2、pom.xml文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http:…...
深度学习代码解读——自用
代码来自:GitHub - ChuHan89/WSSS-Tissue 借助了一些人工智能 2_generate_PM.py 功能总结 该代码用于 生成弱监督语义分割(WSSS)所需的伪掩码(Pseudo-Masks),是 Stage2 训练的前置步骤。其核心流程为&a…...
文件与目录权限
目录 文件权限 文件读权限(r) 文件写权限(w) 文件可执行权限(x) 目录权限 目录读权限(r) 目录写权限(w) 文件可执行权限(x)(与文件权限最大不同之处) 注意 在 Linux 系统中,…...
算法005——有效三角形个数
力扣——有效三角形个数点击链接跳转 判断三条边是否能组成三角形,大家第一时间想到的就是两边之和大于第三边 但是运用这个方法,我们需要判断三次,有一个更简单的方法,只需要判断一次 因为 C 已经是三边之中最大的了ÿ…...
Facebook 的隐私保护数据存储方案研究
Facebook 的隐私保护数据存储方案研究 在这个信息爆炸的时代,数据隐私保护已成为公众关注的热点。Facebook,作为全球最大的社交媒体平台之一,承载着海量用户数据,其隐私保护措施和数据存储方案对于维护用户隐私至关重要。本文将深…...
如何高效利用Spring中的@Cacheable注解?
在现代软件开发中,缓存是提升应用性能的重要手段。Spring框架提供了Cacheable注解,帮助开发者轻松实现缓存机制。今天我们就来详细聊聊Cacheable注解的使用,看看它是如何让我们的应用更加高效的! Cacheable注解的核心功能是缓存方…...
Qt 进度条与多线程应用、基于 Qt 的文件复制工具开发
练习1:Qt 进度条与多线程应用 题目描述 开发一个基于 Qt 的应用程序,该应用程序包含一个水平进度条(QSlider),并且需要通过多线程来更新进度条的值。请根据以下要求完成代码: 界面设计: 使用 QS…...
软件工程---构件
在软件工程中,构件是一个独立的、可复用的软件单元,它具有明确的功能、接口和行为,并且可以在不同的环境中加以集成和复用。构件的概念是软件架构和组件化开发的核心思想之一,其目的是促进软件系统的模块化、可维护性和可扩展性。…...
【算法 C/C++】二维差分
2025 - 03 - 08 - 第 71 篇 Author: 郑龙浩 / 仟濹 【二维差分】 文章目录 前缀和与差分 - 我的博客差分(二维)1 大体思路 | 一些区间加某数的最终结果2 二维差分原理3 例题 前缀和与差分 - 我的博客 一维前缀和 【算法 C/C】一维前缀和 一维差分 【算法 C/C】一维差分 二维前…...
灰色地带规避:知识产权校验API的商标库模糊匹配算法
在反向海淘或其他电商业务场景中,为了规避知识产权方面的灰色地带,开发知识产权校验 API 并运用商标库模糊匹配算法是很有必要的。以下将详细介绍商标库模糊匹配算法的设计与实现: 算法设计思路 商标库模糊匹配算法的核心目标是在给定一个待匹…...
LINUX网络基础 [五] - HTTP协议
目录 HTTP协议 预备知识 认识 URL 认识 urlencode 和 urldecode HTTP协议格式 HTTP请求协议格式 HTTP响应协议格式 HTTP的方法 HTTP的状态码 编辑HTTP常见Header HTTP实现代码 HttpServer.hpp HttpServer.cpp Socket.hpp log.hpp Makefile Web根目录 H…...
嵌入式人工智能应用-第6章 人脸检测
嵌入式人工智能应用 人脸检测 嵌入式人工智能应用1 人脸检测1.1 CNN 介绍1.2 人脸检测原理1.3 MTCNN介绍1.4 NCNN介绍2 系统安装2.1 安装依赖库NCNN2.2 运行对应的库3 总结1 人脸检测 1.1 CNN 介绍 卷积神经网络。卷积是什么意思呢?从数学上说,卷积是一种运算。它是我们学习…...
编程考古-Borland历史:《.EXE Interview》对Anders Hejlsberg关于Delphi的采访内容(中)
为了纪念Delphi在2002年2月14日发布的25周年(2020.2.12),这里有一段由.EXE杂志编辑Will Watts于1995年对Delphi首席架构师Anders Hejlsberg进行的采访记录。在这次采访中,Anders讨论了Delphi的设计与发展,以及即将到来的针对Windows 95的32位版本。 Q. 编译器引擎本身是用…...
redis数据类型以及底层数据结构
redis数据类型以及底层数据结构 String:字符串类型,底层就是动态字符串,使用sds数据结构 Map:有两种数据结构:1.压缩列表:当hash结构中存储的元素个数小于了512个。并且元 …...
C运算符 对比a++、++a、b--、 --b
#include<stdio.h> int main() { int a 21;int b 10;int c, d;c a;//先赋值给c,a本身再运算 c 21, a 22;//c a;//a本身先运算,再赋值给c a 22,c 22;printf("c %d, a %d\n",c, a); d --b;//b本身先运算,再赋值给d …...
Java EE 进阶:Spring MVC(2)
cookie和session的关系 两者都是在客户端和服务器中进行存储数据和传递信息的工具 cookie和session的区别 Cookie是客⼾端保存⽤⼾信息的⼀种机制. Session是服务器端保存⽤⼾信息的⼀种机制. Cookie和Session之间主要是通过SessionId关联起来的,SessionId是Co…...
基于Matlab的人脸识别的二维PCA
一、基本原理 传统 PCA 在处理图像数据时,需将二维图像矩阵拉伸为一维向量,这使得数据维度剧增,引发高计算成本与存储压力。与之不同,2DPCA 直接基于二维图像矩阵展开运算。 它着眼于图像矩阵的列向量,构建协方差矩阵…...
Java 深度复制对象:从基础到实战
目录 一、深度复制的概念二、实现深度复制的方法1. 使用序列化2. 手动实现深度复制 三、总结 在 Java 编程中,对象的复制是一个常见的需求。然而,简单的复制操作(如直接赋值)只会复制对象的引用,而不是创建一个新的对象…...
【Java开发指南 | 第三十五篇】Maven + Tomcat Web应用程序搭建
读者可订阅专栏:Java开发指南 |【CSDN秋说】 文章目录 前言Maven Tomcat Web应用程序搭建1、使用Maven构建新项目2、单击项目,连续按两次shift键,输入"添加",选择"添加框架支持"3、选择Java Web程序4、点击&…...
TCP三次握手,四次挥手;多进程、多线程实现并发服务器
三次握手,四次挥手 三次握手示意图: SYN、ACK是TCP协议头里面的标志位 同步 SYN:仅在三次握手建立 TCP 连接时有效。当 SYN 1 而 ACK 0 时,表明这是一个连接请求报文段,对方若同意建立连接,则应在相应的…...
Java基础系列:深入理解八大基本数据类型及避坑指南
目录 一、基本数据类型概述 八大类型速查表 二、各类型详解与常见陷阱 1. 整型家族(byte/short/int/long) 2. 浮点型(float/double) 3. 字符型(char) 4. 布尔型(boolean) 三…...
【Gaussian Model】高斯分布模型
目录 高斯分布模型用于异常检测(Gaussian Model for Anomaly Detection)1. 高斯分布简介2. 高斯分布模型用于异常检测(1) 训练阶段:估计数据分布(2) 检测阶段:计算概率判断异常点 3. 示例代码4. 高斯分布异常检测的优缺点优点缺点…...
Unity--Cubism Live2D模型使用
了解LIVE2D在unity的使用--前提记录 了解各个组件的作用 Live2D Manuals & Tutorials 这些文件都是重要的控制动画参数的 Cubism Editor是编辑Live2D的工具,而导出的数据的类型,需要满足以上的条件 SDK中包含的Cubism的Importer会自动生成一个Pref…...
Day4 C语言与画面显示练习
文章目录 1. harib01a例程2. harib01b例程3. harib01e例程4. harib01f例程5. harib01h例程 1. harib01a例程 上一章主要是将画面搞成黑屏,如果期望做点什么图案,只需要再VRAM里写点什么就好了,使用nask汇编语言实现一个函数write_mem8&#…...
【redis】全局命令exists、del、expire、ttl(惰性删除和定期删除)
exists——判定 key 是否存在 语法: exists key [key...] # 返回值:key 存在的个数针对多个 key 来说,是非常有用的时间复杂度 O ( 1 ) O(1) O(1) Redis 组织这些 key 就是按照哈希表的方式来组织的。Redis 支持很多数据结构指的是 value …...
VUE3项目的文档结构分析
1. Vue 3 项目的文档结构 Vue 3 项目通常基于 Vue CLI 或 Vite 等工具创建,其文档结构如下: 常见目录结构 my-vue-project/ ├── public/ # 静态资源目录 │ ├── index.html # 入口页面 ├── src/ …...
Linux笔记---自定义shell
目录 前言 1. 程序框架 2. 打印命令行提示符 2.1 获取用户名(GetUserName) 2.2 获取主机名(GetHostName) 2.3 获取工作目录(GetPwd) 3. 获取命令行输入 4. 判断是否有重定向 5. 解析命令行 6. 内建命令 6.1 内建命令的特点 6.2 常见内建命令 6.3 内建命令 vs 外部命…...
步进电机软件细分算法解析与实践指南
1. 步进电机细分技术概述 步进电机是一种将电脉冲信号转换为角位移的执行机构,其基本运动单位为步距角。传统步进电机的步距角通常为 1.8(对应 200 步 / 转),但在高精度定位场景下,这种分辨率已无法满足需求。细分技术…...
mapbox开发小技巧
自定义图标 // 1、单个图标 const url ./static/assets/symbols/code24x24/VIDEO.png // 图标路径 map.loadImage(url ,(error, image) > {if (error) throw errormap.addImage(video-icon, image) })// 2、雪碧图利用canvas // json和png图片 function getStyleImage(fil…...
ApoorvCTF Rust语言逆向实战
上周参加了国外的比赛,名称叫:ApoorvCTF 看一下老外的比赛跟我们有什么不同,然后我根据国内比赛对比发现,他们考点还是很有意思的,反正都是逆向,哈哈哈 Rusty Vault 题目描述: In the heart…...
IntersectionObserver接口介绍
IntersectionObserver API 是浏览器提供的一个用于异步观察目标元素与其祖先元素或视口(Viewport)交叉状态(即是否进入或离开视口)的接口。在 IntersectionObserver 出现之前,开发者通常需要通过监听 scroll 事件或使用…...
AI壁纸进阶宝典:让创作效率与质量飞速提升的法门
在数字化创意浪潮席卷的当下,AI壁纸以其独特魅力和无限可能,吸引了众多设计爱好者和专业设计师的目光。然而,如何在众多创作者中脱颖而出,打造令人惊艳的AI壁纸呢?本文将从基础到进阶,全方位剖析AI壁纸创作…...
Releases(发布) 和 版本管理 是两个紧密相关的概念
在软件开发和维护中,Releases(发布) 和 版本管理 是两个紧密相关的概念,特别是在开源项目或企业软件开发中。 1. Releases(发布) Release 是指软件的一个正式发布版本,通常经过开发、测试、修复 Bug,并被认为是足够稳定和可用于生产环境的版本。 主要特点 里程碑:通…...
从零开始用react + tailwindcss + express + mongodb实现一个聊天程序(十二) socketio 消息处理
1.后端 在message.controller.js中 在sendMessage方法中 每当我们发送消息 需要socketio把这个消息转发给 接收人 加入转发逻辑 // 把消息发给指定的用户的socket const receiverSocketId getReceiverSocketId(receiverId); if(receiverSocketId) { io.to(receiverSocket…...
【运维篇】KubeSphere-02(经验汇总)
一、使用建议 1.对于数据库、对像存储比较重的要不能丢失,有异地存储备份需求的有状态服务,不建议采用k8s进行部署,会导致运维难度更大。 2.对于中间件如redis、MQ、harbor、seata、nacos、zookeeper可采用k8s部署。 3.对于无状态服务tomc…...
8.大模型微调学习案例:基于 Hugging Face、8位量化与 LoRA 适配器的方案
文章目录 一、引言二、数据预处理与构建数据集2.1 加载 JSON 数据2.2 构造训练样本2.3 构建 Hugging Face 数据集与分词2.4 添加标签字段2.5 划分训练集与验证集 三、模型加载、量化与适配器配置3.1 配置设备与显存使用3.2 配置 8 位量化3.3 加载预训练模型并映射设备3.4 为 8 …...
用分页干掉显存浪费!聊聊VLLM的PagedAttention
不知道你在部署模型的时候,有没有经历过这样的抓狂时刻——跑大模型时显卡显存明明没有占满,程序却报错OOM(内存不足)?表面看是显存不足,背后其实是KVCache碎片化和重复存储这个"隐形刺客"在作祟…...