argc
:命令行参数的个数。
argv
:是个数组,每个数组元素都是指向一个字符串的 char *
,里边存储的内容是所有命令行参数。
argv 内存之后接着就是连续的环境变量参数信息内存,里边存储的内容是可执行程序执行时有关的所有环境变量参数信息,可以通过一个全局的 environ
(char **
)访问,environ
内存和 argv
内存是紧紧挨着的。
修改可执行程序名称的实现思路:
- 重新分配一块内存,用来保存
environ
中的内容; - 修改
argv[0]
所指向的内存。
ngx_setproctitle.cxx:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "ngx_global.h"
// 设置可执行程序的标题:分配内存并把环境变量拷贝到新内存中来
void ngx_init_setproctitle()
{
int i;
// 统计环境变量所占的空间大小,注意判断方法是environ[i]是否为空作为环境变量结束标记
for (i = 0; environ[i]; i++)
{
g_environlen += strlen(environ[i]) + 1; // +1是因为末尾有\0,是占实际内存位置的,要算进来
}
gp_envmem = new char[g_environlen];
memset(gp_envmem, 0, g_environlen); // 内存要清空,防止出现问题
char* ptmp = gp_envmem;
// 把原来的内存内容搬到新地方来
for (i = 0; environ[i]; i++)
{
size_t size = strlen(environ[i]) + 1 ; // 不要忘记+1,否则内存全乱套了,因为strlen是不包括字符串末尾的\0的
strcpy(ptmp, environ[i]); // 把原环境变量内容拷贝到新内存中
environ[i] = ptmp; // 然后还要让新环境变量指向这段新内存
ptmp += size;
}
return;
}
// 设置可执行程序的标题:修改argv[0]所指向的内存
void ngx_setproctitle(const char* title)
{
// 这里假设所有的命令行参数我们都不需要了,可以被随意覆盖
// 这里假设新标题所占的空间大小不会超过原argv和environ的内存总和
// 计算新标题的长度
size_t ititlelen = strlen(title);
// 计算原始的argv那块内存的总长度(包括各种参数)
size_t e_environlen = 0;
for (int i = 0; g_os_argv[i]; i++)
{
e_environlen += strlen(g_os_argv[i]) + 1;
}
size_t esy = e_environlen + g_environlen; // 原argv和environ的内存总和
if (esy <= ititlelen) // 注意字符串末尾多了个\0,所以这里的判断是<=,也就是说==都算存不下
{
return;
}
// 空间够保存新标题的,继续走下来
// 设置后续的命令行参数为空,表示argv[]中只有一个元素了,这是个好习惯,防止后续argv被滥用,因为很多判断是用argv[]==NULL来做结束标记判断的
g_os_argv[1] = NULL;
// 把新标题弄进来,注意原来的命令行参数都会被覆盖掉,不要再使用这些命令行参数,而且g_os_argv[1]已经被设置为NULL了
char* ptmp = g_os_argv[0]; // 让ptmp指向g_os_argv所指向的内存
strcpy(ptmp, title);
ptmp += ititlelen; // 跳过标题
// 把剩余的原argv和environ所占的内存全部清0,否则在ps命令的cmd列可能会出现一些没有被覆盖的残余内容
size_t cha = esy - ititlelen; // 内存总和减去标题字符串长度(不含字符串末尾的\0)剩余的大小就是要memset的
memset(ptmp, 0, cha);
return;
}
nginx.cxx:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "ngx_c_conf.h" // 和配置文件处理有关的类,名字带c_表示和类有关
#include "ngx_signal.h"
#include "ngx_func.h" // 各种函数声明
// 和设置标题有关的全局量
char** g_os_argv; // 原始命令行参数数组,在main中会被赋值
char* gp_envmem = NULL; // 指向手动分配的env环境变量的内存
int g_environlen = 0; // 环境变量所占内存大小
int main(int argc, char* const* argv)
{
g_os_argv = (char **) argv;
ngx_init_setproctitle(); // 把环境变量搬家
// 我们在main中,先把配置读出来,供后续使用
CConfig* p_config = CConfig::GetInstance(); // 单例类
if (p_config->Load("nginx.conf") == false) // 把配置文件内容载入到内存
{
printf("配置文件载入失败,退出!\n");
exit(1);
}
// 前提是保证所有命令行参数我们都不用了
ngx_setproctitle("nginx: master process");
// 获取配置文件信息
int port = p_config->GetIntDefault("ListenPort", 0); // 0是缺省值
printf("port=%d\n", port);
const char* pDBInfo = p_config->GetString("DBInfo");
if (pDBInfo != NULL)
{
printf("DBInfo=%s\n", pDBInfo);
}
for (;;)
{
sleep(1);
printf("休息1秒\n");
}
// 对于因为设置可执行程序标题导致的环境变量分配的内存,我们应该释放
if (gp_envmem)
{
delete[] gp_envmem;
gp_envmem = NULL;
}
printf("程序退出,再见!\n");
return 0;
}