栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

守护进程,一份nginx实现,一份我的实现,看着拿呗

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

守护进程,一份nginx实现,一份我的实现,看着拿呗

文章目录
    • 示例出处
    • 守护进程概念
      • 创建步骤
      • 存在即合理
    • nginx中的daemon
    • 缝缝补补又一套

示例出处

这个守护进程的示例是我从nginx的源码当中剥离出来的。

nginx的源码是比muduo要复杂些哈,muduo跟我以前写过的服务端项目有很多共通之处,就相当于是剥离了业务代码的网络层框架,所以看起来也比较亲切。这个nginx就感觉稍微有点陌生哈。

所以我决定一块一块能用的我先剥出来。


守护进程概念

守护进程是一个在后台运行并且不受任何终端控制的进程。

守护进程没有控制终端,因此当某些情况发生时,不管是一般的报告性信息,还是需由管理员处理的紧急信息,都需要以某种方式输出。

创建步骤

1、创建“孤儿进程”,形式上与终端脱离;
2、让这个“孤儿进程”成为新会话的组长,防止进程被原会话中其他进程干扰;
3、改变工作目录并重设文件创建掩码;
4、关闭文件描述符,因为没必要开着了。

以上2/3/4都是在消除父进程的印记。

还看到有些人说,应该先屏蔽些信号,省的出师未捷身先死哈。想屏蔽就屏蔽呗,也不差写那四五行代码。

存在即合理

1)终端要干别的事儿了,后边凉快的地方呆着去。
2)避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。逍遥吧!


接下来我们看看nginx里面的守护进程实现哈,当然,我们要带着辩证的角度来看,要是看到它省略了几句啥,咱可以自己补上嘛,有试无害嘛。

nginx中的daemon
ngx_int_t ngx_daemon(ngx_log_t *log)	
{
    int  fd;

		//要成为守护进程,首先要成为孤儿,进孤儿院
		
    switch (fork()) {
    case -1:
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
        return NGX_ERROR;

    case 0:
        break;

    default:
        exit(0);
    }

		
    if (setsid() == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
        return NGX_ERROR;
    }

		
    umask(0);


		
    fd = open("/dev/null", O_RDWR);	//难怪在好多地方有看到这么个写法,当时就不知道是干嘛的
    if (fd == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                      "open("/dev/null") failed");
        return NGX_ERROR;
    }

    if (dup2(fd, STDIN_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
        return NGX_ERROR;
    }

    if (dup2(fd, STDOUT_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
        return NGX_ERROR;
    }

#if 0
    if (dup2(fd, STDERR_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
        return NGX_ERROR;
    }
#endif

    if (fd > STDERR_FILENO) {
        if (close(fd) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
            return NGX_ERROR;
        }
    }

		
    return NGX_OK;
}

是吧,人家的实现里面有些细节我们前面还是没有考虑到的,不过我们前面考虑到的一些细节人家也是没有采用的,不知道是不是没有必要还是咋滴,我还是将两者结合一下补一份哈,有需要的看情况自取。


缝缝补补又一套
#include  
#include  
#include 
#include 
#include  
#include  
#include  
#include 
#include 
#include 
 
int init_daemon(void)
{ 
	int i;
	
	// 1)屏蔽一些控制终端操作的信号
	//这些nginx在创建进程的时候设定了哈
	signal(SIGTTOU,SIG_IGN); 
	signal(SIGTTIN,SIG_IGN); 
	signal(SIGTSTP,SIG_IGN); 
	signal(SIGHUP ,SIG_IGN);
 
	// 2)创建孤儿进程
	switch (fork()) {
    case -1:
        return -1;
    case 0:
        break;
    default:
        exit(0);
  }
    
	// 3)脱离控制终端、登录会话和进程组
	setsid();  
	
	// 4)禁止进程重新打开控制终端
	
	switch (fork()) {
    case -1:
        return -1;
    case 0:
        break;
    default:	// 结束第一子进程,第二子进程继续(第二子进程不再是会话组长)
        exit(0);
  }
	
	// 5)关闭打开的文件描述符
	
	for(i=0; i< NOFILE; ++i){
		close(i);
	}
	
	// 6)改变当前工作目录
	//这个nginx也没有做
	chdir("/"); 
	
	// 7)重设文件创建掩模
	umask(0);  
	
	// 8)重定向标准流
	
    fd = open("/dev/null", O_RDWR);	//难怪在好多地方有看到这么个写法,当时就不知道是干嘛的
    if (fd == -1) {
        return -1;
    }

    if (dup2(fd, STDIN_FILENO) == -1) {
        return -1;
    }

    if (dup2(fd, STDOUT_FILENO) == -1) {
        return -1;
    }

#if 0
    if (dup2(fd, STDERR_FILENO) == -1) {
        return -1;
    }
#endif
		//把fd关了,nginx可真省,难怪前面那些都不要了
		//还是那句话,个人看个人情况自取
    if (fd > STDERR_FILENO) {
        if (close(fd) == -1) {
            return -1;
        }
    }

	// 9)处理 SIGCHLD 信号
	
	signal(SIGCHLD,SIG_IGN);
	
	return 0; 
} 
 
int main(int argc, char *argv[]) 
{
	init_daemon();
	
	while(1);
 
	return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/288955.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号