【tag-005】Linux C++ 网络编程架构之守护进程

本节我们实现一个守护进程,使得我们的程序可以脱离终端,运行在后台。

  • 配置
    我们希望通过配置文件,可以选择程序是否以守护进程的方式启动,因此首先在配置文件 nginx_sim.conf 中进行如下配置
# 注释行
# 每个有效配置项用 = 处理,= 前不超过40字符,= 后不超过400字符

# 以 [ 开头表示组信息,也等价于注释行
Log = logs/error2.log
LogLevel = 5

#表示程序是否以守护进程启动
Daemon = 1

  • 实现一个守护进程函数
    在文件 ngx_func.h 中声明函数 int ngx_deamon();在我们的目录结构中已经创建了专门存放进程相关的目录 proc,在此目录下新建 ngx_deamon.cxx 文件,在此文件我们实现这个函数。
/**
 * @brief 守护进程的初始化
 * @return -1: 执行失败; 子进程:0;父进程:1
 * 
 */
int ngx_deamon()
{
    switch(fork())
    {
    case -1:
        ngx_log_error_core(NGX_LOG_EMERG,errno,"ngx_deamon()中的fork()失败!");
        return -1;
    case 0:
        break;
    default:
        return 1;
    }

    //记录进程的ID
    ngx_parent = ngx_pid;
    ngx_pid = getpid();

    //脱离终端
    if(-1 == setsid())
    {
        ngx_log_error_core(NGX_LOG_EMERG,errno,"进程脱离终端失败!");
    }

    //取消文件权限的限制
    umask(0);

    int fd = open("/dev/null", O_RDWR);
    if (fd == -1) 
    {
        ngx_log_error_core(NGX_LOG_EMERG,errno,"ngx_daemon()中open(\"/dev/null\")失败!");        
        return -1;
    }
    //先关闭STDIN_FILENO,类似于指针指向null,让/dev/null成为标准输入;
    if (dup2(fd, STDIN_FILENO) == -1) 
    {
        ngx_log_error_core(NGX_LOG_EMERG,errno,"ngx_daemon()中dup2(STDIN)失败!");        
        return -1;
    }
    //再关闭STDIN_FILENO,类似于指针指向null,让/dev/null成为标准输出;
    if (dup2(fd, STDOUT_FILENO) == -1) 
    {
        ngx_log_error_core(NGX_LOG_EMERG,errno,"ngx_daemon()中dup2(STDOUT)失败!");
        return -1;
    }
    if (fd > STDERR_FILENO)
     {
        //释放资源这样这个文件描述符就可以被复用;不然这个数字【文件描述符】会被一直占着;
        if (close(fd) == -1)  
        {
            ngx_log_error_core(NGX_LOG_EMERG,errno, "ngx_daemon()中close(fd)失败!");
            return -1;
        }
    }
    return 0; //子进程返回0
}
  • 测试
    我们在 main 函数中,设置进程名之后加入以下代码测试
//守护进程
if(CConfig::GetInstance()->GetIntDefault("Daemon",0) == 1)
{
    int cdaemonresult = ngx_deamon();
    if(cdaemonresult == -1) //fork()失败
    {
        goto lblexit;
    }
    if(cdaemonresult == 1)
    {
        //这是原始的父进程
        freereSource();   //只有进程退出了才goto到 lblexit,用于提醒用户进程退出了
                          //而我现在这个情况属于正常fork()守护进程后的正常退出,不应该跑到lblexit()去执行,因为那里有一条打印语句标记整个进程的退出,这里不该限制该条打印语句;
        return 0;  //整个进程直接在这里退出
    }
    //走到这里,成功创建了守护进程并且这里已经是fork()出来的进程,现在这个进程做了master进程
    g_daemonized = 1;    //守护进程标记,标记是否启用了守护进程模式,0:未启用,1:启用了
}

运行我们的程序,可以看到已经脱离了终端
在这里插入图片描述
查看一下后台进程可以看到我们的进程正在运行
在这里插入图片描述
Note: 我们的程序中 master 进程其实并非最原始的进程,最原始的进程其实退出了,master 进程也是由最原始的进程 fork 出来的子进程。至于为何这样做,主要是这个原始的主进程是进程组的组长,调用 setsid 函数脱离终端会失败。

至此,我们的程序已经可以以守护进程的方式启动了,下一节将继续我们的进程话题,为我们的程序创建多个 worker 子进程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值