Linux设置进程名称(标题) ( 7) -【Linux通信架构系列 】

news2024/11/22 12:02:48

系列文章目录

C++技能系列
Linux通信架构系列
C++高性能优化编程系列
深入理解软件架构设计系列
高级C++并发线程编程

期待你的关注哦!!!
在这里插入图片描述

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.

@TOC
nginx.c


//整个程序入口函数放这里
/*
王健伟老师 《Linux C++通讯架构实战》
商业级质量的代码,完整的项目,帮你提薪至少10K
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h> 
#include <errno.h>
#include <arpa/inet.h>

#include "ngx_macro.h"         //各种宏定义
#include "ngx_func.h"          //各种函数声明
#include "ngx_c_conf.h"        //和配置文件处理相关的类,名字带c_表示和类有关
#include "ngx_c_socket.h"      //和socket通讯相关
#include "ngx_c_memory.h"      //和内存分配释放等相关
#include "ngx_c_threadpool.h"  //和多线程有关

//本文件用的函数声明
static void freeresource();

//和设置标题有关的全局量
size_t  g_argvneedmem=0;        //保存下这些argv参数所需要的内存大小
size_t  g_envneedmem=0;         //环境变量所占内存大小
int     g_os_argc;              //参数个数 
char    **g_os_argv;            //原始命令行参数数组,在main中会被赋值
char    *gp_envmem=NULL;        //指向自己分配的env环境变量的内存,在ngx_init_setproctitle()函数中会被分配内存
int     g_daemonized=0;         //守护进程标记,标记是否启用了守护进程模式,0:未启用,1:启用了

//socket/线程池相关
CSocekt      g_socket;          //socket全局对象
CThreadPool  g_threadpool;      //线程池全局对象

//和进程本身有关的全局量
pid_t   ngx_pid;                //当前进程的pid
pid_t   ngx_parent;             //父进程的pid
int     ngx_process;            //进程类型,比如master,worker进程等

sig_atomic_t  ngx_reap;         //标记子进程状态变化[一般是子进程发来SIGCHLD信号表示退出],sig_atomic_t:系统定义的类型:访问或改变这些变量需要在计算机的一条指令内完成
                                   //一般等价于int【通常情况下,int类型的变量通常是原子访问的,也可以认为 sig_atomic_t就是int类型的数据】                                   

//程序主入口函数----------------------------------
int main(int argc, char *const *argv)
{   
    //time_t mytime = time(NULL);
    //printf("time = %u",mytime);
    //exit(0);
    //#ifdef _POSIX_THREADS 
    //    printf("henhao");
    //#endif    
    //exit(0);
    //printf("unsigned long sizeof=%d",sizeof(unsigned long));
    //printf("htonl(100)=%d",htonl(100));
    //printf("ntohl(htonl(100)=%d",ntohl(htonl(100)));
    //exit(0);
    //printf("EAGAIN=%d,EWOULDBLOCK=%d,EINTR=%d",EAGAIN,EWOULDBLOCK,EINTR);
    //ssize_t n = -1;
    //printf("ssize_t n = %d\n",n);
    //exit(0);
    int exitcode = 0;           //退出代码,先给0表示正常退出
    int i;                      //临时用
    //CMemory *p_memory;

    //(1)无伤大雅也不需要释放的放最上边    
    ngx_pid    = getpid();      //取得进程pid
    ngx_parent = getppid();     //取得父进程的id 
    //统计argv所占的内存
    g_argvneedmem = 0;
    for(i = 0; i < argc; i++)  //argv =  ./nginx -a -b -c asdfas
    {
        g_argvneedmem += strlen(argv[i]) + 1; //+1是给\0留空间。
    } 
    //统计环境变量所占的内存。注意判断方法是environ[i]是否为空作为环境变量结束标记
    for(i = 0; environ[i]; i++) 
    {
        g_envneedmem += strlen(environ[i]) + 1; //+1是因为末尾有\0,是占实际内存位置的,要算进来
    } //end for

    g_os_argc = argc;           //保存参数个数
    g_os_argv = (char **) argv; //保存参数指针

    //全局量有必要初始化的
    ngx_log.fd = -1;                  //-1:表示日志文件尚未打开;因为后边ngx_log_stderr要用所以这里先给-1
    ngx_process = NGX_PROCESS_MASTER; //先标记本进程是master进程
    ngx_reap = 0;                     //标记子进程没有发生变化
   
    //(2)初始化失败,就要直接退出的
    //配置文件必须最先要,后边初始化啥的都用,所以先把配置读出来,供后续使用 
    CConfig *p_config = CConfig::GetInstance(); //单例类
    if(p_config->Load("nginx.conf") == false) //把配置文件内容载入到内存            
    {   
        ngx_log_init();    //初始化日志
        ngx_log_stderr(0,"配置文件[%s]载入失败,退出!","nginx.conf");
        //exit(1);终止进程,在main中出现和return效果一样 ,exit(0)表示程序正常, exit(1)/exit(-1)表示程序异常退出,exit(2)表示表示系统找不到指定的文件
        exitcode = 2; //标记找不到文件
        goto lblexit;
    }
    //(2.1)内存单例类可以在这里初始化,返回值不用保存
    CMemory::GetInstance();	
        
    //(3)一些必须事先准备好的资源,先初始化
    ngx_log_init();             //日志初始化(创建/打开日志文件),这个需要配置项,所以必须放配置文件载入的后边;     
        
    //(4)一些初始化函数,准备放这里        
    if(ngx_init_signals() != 0) //信号初始化
    {
        exitcode = 1;
        goto lblexit;
    }        
    if(g_socket.Initialize() == false)//初始化socket
    {
        exitcode = 1;
        goto lblexit;
    }

    //(5)一些不好归类的其他类别的代码,准备放这里
    ngx_init_setproctitle();    //把环境变量搬家

    //------------------------------------
    //(6)创建守护进程
    if(p_config->GetIntDefault("Daemon",0) == 1) //读配置文件,拿到配置文件中是否按守护进程方式启动的选项
    {
        //1:按守护进程方式运行
        int cdaemonresult = ngx_daemon();
        if(cdaemonresult == -1) //fork()失败
        {
            exitcode = 1;    //标记失败
            goto lblexit;
        }
        if(cdaemonresult == 1)
        {
            //这是原始的父进程
            freeresource();   //只有进程退出了才goto到 lblexit,用于提醒用户进程退出了
                              //而我现在这个情况属于正常fork()守护进程后的正常退出,不应该跑到lblexit()去执行,因为那里有一条打印语句标记整个进程的退出,这里不该限制该条打印语句;
            exitcode = 0;
            return exitcode;  //整个进程直接在这里退出
        }
        //走到这里,成功创建了守护进程并且这里已经是fork()出来的进程,现在这个进程做了master进程
        g_daemonized = 1;    //守护进程标记,标记是否启用了守护进程模式,0:未启用,1:启用了
    }

    //(7)开始正式的主工作流程,主流程一致在下边这个函数里循环,暂时不会走下来,资源释放啥的日后再慢慢完善和考虑    
    ngx_master_process_cycle(); //不管父进程还是子进程,正常工作期间都在这个函数里循环;
        
    //--------------------------------------------------------------    
    //for(;;)    
    //{
    //    sleep(1); //休息1秒        
    //    printf("休息1秒\n");        
    //}
      
    //--------------------------------------
lblexit:
    //(5)该释放的资源要释放掉
    ngx_log_stderr(0,"程序退出,再见了!");
    freeresource();  //一系列的main返回前的释放动作函数
    //printf("程序退出,再见!\n");    
    return exitcode;
}

//专门在程序执行末尾释放资源的函数【一系列的main返回前的释放动作函数】
void freeresource()
{
    //(1)对于因为设置可执行程序标题导致的环境变量分配的内存,我们应该释放
    if(gp_envmem)
    {
        delete []gp_envmem;
        gp_envmem = NULL;
    }

    //(2)关闭日志文件
    if(ngx_log.fd != STDERR_FILENO && ngx_log.fd != -1)  
    {        
        close(ngx_log.fd); //不用判断结果了
        ngx_log.fd = -1; //标记下,防止被再次close吧        
    }
}

ngx_global.h

#include <signal.h> 

#include "ngx_c_socket.h"
#include "ngx_c_threadpool.h"

//一些比较通用的定义放在这里,比如typedef定义
//一些全局变量的外部声明也放在这里

//类型定义----------------

//结构定义
typedef struct _CConfItem
{
	char ItemName[50];
	char ItemContent[500];
}CConfItem,*LPCConfItem;

//和运行日志相关 
typedef struct
{
	int    log_level;   //日志级别 或者日志类型,ngx_macro.h里分0-8共9个级别
	int    fd;          //日志文件描述符

}ngx_log_t;


//外部全局量声明
extern size_t        g_argvneedmem;
extern size_t        g_envneedmem; 
extern int           g_os_argc; 
extern char          **g_os_argv;
extern char          *gp_envmem; 
extern int           g_daemonized;
extern CSocekt       g_socket;  
extern CThreadPool   g_threadpool;

extern pid_t         ngx_pid;
extern pid_t         ngx_parent;
extern ngx_log_t     ngx_log;
extern int           ngx_process;   
extern sig_atomic_t  ngx_reap;   

ngx_func.h

//函数声明放在这个头文件里-------------------------------------------

#ifndef __NGX_FUNC_H__
#define __NGX_FUNC_H__

//字符串相关函数
void   Rtrim(char *string);
void   Ltrim(char *string);

//设置可执行程序标题相关函数
void   ngx_init_setproctitle();
void   ngx_setproctitle(const char *title);

//和日志,打印输出有关
void   ngx_log_init();
void   ngx_log_stderr(int err, const char *fmt, ...);
void   ngx_log_error_core(int level,  int err, const char *fmt, ...);
u_char *ngx_log_errno(u_char *buf, u_char *last, int err);
u_char *ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...);
u_char *ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...);
u_char *ngx_vslprintf(u_char *buf, u_char *last,const char *fmt,va_list args);

//和信号/主流程相关相关
int    ngx_init_signals();
void   ngx_master_process_cycle();
int    ngx_daemon();
void   ngx_process_events_and_timers();


#endif  

ngx_setproctitle.cxx

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>  //env
#include <string.h>

#include "ngx_global.h"

//设置可执行程序标题相关函数:分配内存,并且把环境变量拷贝到新内存中来
void ngx_init_setproctitle()
{   
    //这里无需判断penvmen == NULL,有些编译器new会返回NULL,有些会报异常,但不管怎样,如果在重要的地方new失败了,你无法收场,让程序失控崩溃,助你发现问题为好; 
    gp_envmem = new char[g_envneedmem]; 
    memset(gp_envmem,0,g_envneedmem);  //内存要清空防止出现问题

    char *ptmp = gp_envmem;
    //把原来的内存内容搬到新地方来
    for (int 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;
}

//设置可执行程序标题
void ngx_setproctitle(const char *title)
{
    //我们假设,所有的命令 行参数我们都不需要用到了,可以被随意覆盖了;
    //注意:我们的标题长度,不会长到原始标题和原始环境变量都装不下,否则怕出问题,不处理
    
    //(1)计算新标题长度
    size_t ititlelen = strlen(title); 

    //(2)计算总的原始的argv那块内存的总长度【包括各种参数】    
    size_t esy = g_argvneedmem + g_envneedmem; //argv和environ内存总和
    if( esy <= ititlelen)
    {
        //你标题多长啊,我argv和environ总和都存不下?注意字符串末尾多了个 \0,所以这块判断是 <=【也就是=都算存不下】
        return;
    }

    //空间够保存标题的,够长,存得下,继续走下来    

    //(3)设置后续的命令行参数为空,表示只有argv[]中只有一个元素了,这是好习惯;防止后续argv被滥用,因为很多判断是用argv[] == NULL来做结束标记判断的;
    g_os_argv[1] = NULL;  

    //(4)把标题弄进来,注意原来的命令行参数都会被覆盖掉,不要再使用这些命令行参数,而且g_os_argv[1]已经被设置为NULL了
    char *ptmp = g_os_argv[0]; //让ptmp指向g_os_argv所指向的内存
    strcpy(ptmp,title);
    ptmp += ititlelen; //跳过标题

    //(5)把剩余的原argv以及environ所占的内存全部清0,否则会出现在ps的cmd列可能还会残余一些没有被覆盖的内容;
    size_t cha = esy - ititlelen;  //内存总和减去标题字符串长度(不含字符串末尾的\0),剩余的大小,就是要memset的;
    memset(ptmp,0,cha);
    return;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

技术管理三板斧之第一板斧拿结果-定目标

一、现状&#xff1a; 去年年底今年年初&#xff0c;帮助一家公司做了一次大的系统重构&#xff0c;30多小伙伴&#xff0c;经历一次洗礼&#xff0c;对产品定位&#xff0c;技术选型&#xff0c;目标制定&#xff0c;任务分配&#xff0c;协同开发&#xff0c;测试上线&#x…

JS 启动一个计时器来跟踪某一个操作的占用时长

文章目录 需求分析代码 需求 JS 中想要记录一个操作的占用时长 分析 可以启动一个计时器console.time(name:string)来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字&#xff0c;页面中最多能同时运行 10,000 个计时器。 当以此计时器名字为参数调用 console.timeE…

蓝桥杯专题-试题版-【龟兔赛跑预测】【回形取数】【阶乘计算】【矩形面积交】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

计算机的性能指标

计算机的主要性能指标: 机器字长: 指参与运算的基本数位, 它是由加法器, 寄存器的数位决定的, 所以及其资产一般等于内部寄存器的大小 数据路通宽度: 数据总线一次能够并行传送信息的位数, 这里所说的数据通路宽度实际是指外部数据总线的宽度 主存容量: 一个存储器所能存储的…

C语言王国探险记之常量的四大护卫

王国探险记系列 文章目录&#xff08;3&#xff09; 前言 一、常量是什么&#xff1f; 二、常量的第一护卫&#xff1a;字面常量 1.什么是字面常量? 三、常量的第二护卫&#xff1a;const修饰的常变量 1.什么是const修饰的常变量? 2&#xff0c;证明const修饰的常变量…

nginx部署多个前端项目

前端采用vue框架&#xff0c;主要介绍在同一个ipport下&#xff08;或域名&#xff09;&#xff0c;通过访问不同的子路径部署多个项目 把前端打包好的项目直接放进 nginx/html 目录下面&#xff0c; 下面展示根据不同的路由模式的nginx配置&#x1f447; 路由采用hash模式 浏…

基于深度学习YOLOv5电动车头盔佩戴检测设计毕业设计

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;625头盔 获取完整源码源文件标注好的数据集(在源码文件夹->yolov5-5.0->VOCdevkit)优秀论文答辩PPT及文稿等 设计总说明 在许多非机动车交通事故中&#xff0c;未佩戴头盔是造成驾驶人受伤或死亡的主要原因&#xf…

永磁电机中的磁钢

稀土永磁最大的应用领域就是永磁电机&#xff0c;电机俗称马达&#xff0c;广义上的电机包含了将电能转换成机械能的电动机&#xff0c;和将机械能转换成电能的发电机&#xff0c;不管是电动机还是发电机&#xff0c;都是利用电磁感应定律或电磁力定律作为基础原理的电气设备。…

【教学类-36-02】动物头饰制作(midjounery动物简笔画四图)

作品展示 &#xff08;用midjounery动物简笔画四图作为头饰上的动物&#xff0c;正方形折纸的辅助黏贴物&#xff09; 背景需求&#xff1a; 1、用midjounery生成简笔画动物图案&#xff08;四张预览&#xff09; 2、收集各种不同的动物的一张图片.png 3、设计一款中班幼儿用…

python spider 爬虫 之 解析 xpath 、jsonpath、BeautifulSoup (-)

Xpath 插件下载及安装 下载地址&#xff1a;https://chrome.zzzmh.cn/info/hgimnogjllphhhkhlmebbmlgjoejdpjl 安装xpath 如果下载的xpath后缀是crx 格式的&#xff0c; 直接改成zip格式&#xff0c;然后直接拖拽到上面的界面中便可&#xff0c; 查看是否安装成功&#xff0c…

DOM操作——获取元素的方式

关注“大前端私房菜”微信公众号&#xff0c;回复暗号【面试宝典】即可免费领取107页前端面试题。 DOM-文档对象模型 DOM&#xff08;Document Object Model&#xff09;&#xff1a;文档对象模型 其实就是操作 html 中的标签的一些能力&#xff0c;或者说是一整套操作文档流的…

10年内打造量子超级计算机,行吗?

光子盒研究院 在未来十年内&#xff0c;微软打算建造一台量子超级计算机。 本周四&#xff0c;微软制定了一个开发自己的量子超级计算机的战略蓝图。设计它的团队将花费至少10年的研究时间&#xff0c;来建造一台能够每秒进行一百万次可靠量子操作的机器。 微软声称&#xff0c…

C++的access()函数

文章目录 函数功能头文件函数原型参数说明示例 函数功能 确定文件是否存在或者判断读写执行权限&#xff1b;确定文件夹是否存在即&#xff0c;检查某个文件的存取方式&#xff0c;比如说是只读方式、只写方式等。如果指定的存取方式有效&#xff0c;则函数返回0&#xff0c;否…

津津乐道设计模式 - 观察者模式详解(学会察言观色再也不怕女朋友生气了)

&#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Micro麦可乐的博客 &#x1f425;《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程&#xff0c;入门到实战 &#x1f33a;《RabbitMQ》…

Nginx 优化配置及详细注释~转

Nginx 优化配置及详细注释 转https://www.cnblogs.com/taiyonghai/p/5610112.html Nginx 的nginx.conf文件&#xff0c;是调优后的&#xff0c;具体影响已经写清楚注释&#xff0c;可以拿来用&#xff0c;有一些设置无效&#xff0c;我备注上了&#xff0c;不知道是不是版本的…

《kafka 核心技术与实战》课程学习笔记(七)

生产者压缩算法 怎么压缩&#xff1f; 压缩&#xff08;compression&#xff09;秉承了用时间去换空间的经典 trade-off 思想&#xff0c;具体来说就是用 CPU 时间去换磁盘空间或网络 I/O 传输量&#xff0c;希望以较小的 CPU 开销带来更少的磁盘占用或更少的网络 I/O 传输。…

初识mysql数据库之基础操作

目录 一、库的操作 1. 创建数据库 2. 数据库的编码集 2.1 数据库的编码问题 2.2 查看系统默认字符集和校验规则 2.3 创建数据库时指定字符集和校验集 2.4 校验规则对数据库的影响 3. 进入数据库 4. 确认自己当前所处的数据库 5. 修改数据库的编码集 6. 查看创建数据…

FPGA解码MIPI视频 OV5647 2line CSI2 720P分辨率采集 提供工程源码和技术支持

目录 1、前言2、Xilinx官方主推的MIPI解码方案3、本 MIPI CSI2 模块性能及其优越性4、我这里已有的 MIPI 编解码方案5、详细设计方案6、vivado工程介绍7、上板调试验证8、福利&#xff1a;工程代码的获取 1、前言 FPGA图像采集领域目前协议最复杂、技术难度最高的应该就是MIPI…

现代民机“飞行管理系统(FMS)”的功能和组成

01 什么是 “飞行管理系统”&#xff1f; 飞行管理系统&#xff08;FMS, Flight Management System&#xff09;&#xff0c;中文简称 “飞管”&#xff0c;是飞机航电系统的重要一员。 FMS 自 20 世纪 70 年代诞生以来&#xff0c;目前已有了跨越式发展。它作为航电关键系统&…

100种思维模型之质量控制理论思维模型-83

质量控制理论思维模型&#xff0c;又叫做戴明环思维模型&#xff0c;即PDCA循环思维模型。 在上世纪50年代&#xff0c;日本的商品和今天中国的商品一样&#xff0c;都是低质低价的代表&#xff0c;后来日本引入了戴明博士的质量控制理论&#xff0c;即PDCA循环理论&#xff0…