守护进程及其范例代码
守护进程理解以及与后台进程区别
守护进程,也就是常说的Daemon进程,是一种长期运行在linux后台的服务进程,并且不与任何控制终端关联。
守护进程的特点
- 生存周期长,只随着系统的开始、关闭而开启、关闭;
- 守护进程和终端没有直接关联;
- 后台运行。
与后台进程的区别
守护进程与后台进程的区别主要体现在与终端的关联性上:
- 后台进程: 当终端退出时,后台进程也随之关闭;
- 守护进程: 守护进程既不会在终端上输出、输入,也不会因为终端的退出而退出
守护进程编写规则
在了解守护进程是如何编写之前,先要了解下面三个内容
- 文件描述符
- 输入输出重定向
- 空设备
文件描述符
文件描述符:正数,用来标识一个文件,当打开一个存在的文件或者创建一个新文件,操作系统都会返回一个文件描述符。可以理解为这个文件描述符就是代表这个文件的,后续对这个文件进行操作的函数,都会用到这个文件描述符作为参数。
Linux下三个特殊的描述符(数字0、1、2)
- 数字0: 标准输入(键盘) 对应的符号常量(宏定义) STDIN_FILENO
- 数字1: 标准输出(屏幕)对应的符号常量(宏定义) STDOUT_FILENO
- 数字2: 标准错误 (屏幕)对应的符号常量(宏定义) STDERR_FILENO
从我个人理解上来说,Linux下一切皆文件,有以下面三点:
- 要像看待/操作文件一样去看待/操作文件描述符;
- 程序运行的同时,这三个文件描述符 0、1、2 会被自动打开,自动指向对应的设备(键盘、屏幕、屏幕);
- 可以把文件描述符看做一个指针,去指向他们代表的文件。
输入输出重定向
输出重定向
让标准输出文件描述符不再指向屏幕,而是去指向另一个文件。
//命令行示例:
ls -la > myoutfile
随便打开一个目录,命令行ls -la 查看目录文件信息
输出重定向到myoutfile文件
观察myoutfile文件内容发现,原本输出到屏幕的内容输出到了文件中
//观察myoutfile文件内容:
cat myoutfile
输入重定向
// An highlighted block
cat < myinfile
类似于输出重定向,输入重定向就是将从键盘输入数据改为从myinfile文件输入,cat将从myinfile文件中获取的数据显示到屏幕上。
空设备
目录位置:/dev/null
功能:类似于黑洞,丢弃一切写入其中的数据。
守护进程虽然可以从终端启动,但是和终端不挂钩,守护进程在后台运行,但是不应该从键盘上接受任何数据,也不应该把输出结果打印到屏幕上或者终端上来,所以,要把守护进程的标准输入,标准输出重定向到空设备中去!
代码范例
int ngx_daemon()
{
int fd;
switch(fork())
{
case -1:
//创建子进程失败。记录错误日志
return-1;
case 0:
//成功创建子进程。
break;
default:
//父进程,直接退出。
exit(0);
}
//只有子进程才能走到这里,只有子进程才能break退出。
if(setsid()==-1) //脱离终端,终端关闭,也与此子进程无关。
{
//记录错误日志
return -1;
}
umask(0);//设置为0,不让它来限制文件权限,以免引起混乱。
fd=open("/dev/null",O_RDWR);//打开黑洞设备,以读写形式。
if(fd==-1)
{
//记录错误日志。
return -1;
}
if(dup2(fd,STDIN_FILENO)==-1) //先关闭STDIN_FILENO,如果之前已经打开
//则将其关闭
{
//记录错误日志。
return -1;
}
if(dup2(fd,STDOUT_FILENO)==-1) //同样也是先关闭STDOUT_FILENO.
{
//记录错误日志。
return -1;
}
if(fd>STDERR_FILENO)//fd应该是3,这里应该成立
{
if(close(fd)==-1)
{
//记录错误日志。
return -1;
}
}
return 1;
}
int main(int argc, char *const *argv)
{
if(ngx_daemon()!=1)
{
//创建守护进程失败。
return -1;
}
else
{
for(;;)
{
sleep(1);
printf("---休息1秒---进程id=%d\n",getpid());
//现在标准输出已经重定向到黑洞中去,打印也看不到结果。
}
}
printf("再见!\n");
return 0;
}