Linux守护进程
1) 守护进程也称为Daemon进程,是Linux中的后台服务进程。守护进程用于执行特定的系统任务。守护进程的生命周期较长,一些守护进程在系统引导时启动,一直运行至系统关闭。
2) Linux系统大多数服务都是用守护进程实现的。
1. 查看系统中的守护进程
ps -axj
父进程ID PPID
进程ID PID
进程组ID PGID
会话期ID SID
终端ID TTY
终端进程组ID TPGID
状态 STAT
用户 UID
运行时间 TIME
指令 COMMAND
2. Linux守护进程编写步骤
1)创建子进程,父进程退出
2)在子进程内创建新会话
3)改变工作目录
4)重设文件权限掩码
5)关闭文件描述符
具体步骤如下:
1. 创建子进程,父进程退出
当父进程退出后,子进程变成了孤儿进程。在Linux内,如果出现了孤儿进程,则自动由1号进程(init进程)收养该进程,也就是说变成了1号进程(init进程)的子进程了。
pid = fork();
If(pid > 0)
{
exit(0);
}
2. 在子进程内创建新会话
首先需要了解两个概念:进程组与会话期
进程组:
进程组是一个或多个进程的集合。进程组号由PGID(Process Group ID)唯一识别。
进程不是孤立的,每个进程都存在父子、兄弟关系,如果某些进程关系相近或者功能相似,那么我们可以将这些进程编成一个进程组。每个进程必定属于一个进程组,也只能属于一个进程组。
每个进程组都有一个组长进程,负责整个进程组的调度工作。组长进程的PID等于进程组的PGID。
会话期:
会话期是一个或多个进程组的集合。
可以使用setsid()函数来创建一个新会话,并让该进程担任会话组长。调用setsid()函数主要有三个功能:
1)让进程摆脱原会话控制
2)让进程摆脱原进程组控制
3)让进程摆脱原控制终端控制
3. 改变工作目录
使用fork()函数创建的子进程复制了父进程的工作目录。由于在进程运行过程中,当前进程的工作目录所在的文件系统是无法卸载的,这会对后续的工作造成一定麻烦(例如需要切换到单用户模式),因此在后台工作的守护进程的工作目录必须改变成其他的不会受到干扰的工作目录。通常情况下,我们将守护进程的工作目录设定为根目录"/"或”/tmp”。
chdir()可以改变进程当前工作目录。
4. 重设文件权限掩码
文件权限掩码是指文件权限中被屏蔽掉的对应位。把文件权限掩码设置为0,可以增加该守护进程的灵活性。
设置文件权限掩码的函数为umask()。
通常使用umask(0)。
5. 关闭文件描述符
新建的子进程会从父进程那里继承所有打开的文件。
在创建完新的会话后,守护进程已经脱离任何控制终端,应当关闭应用不到的文件。
fdtablesize = getdtablesize();
for(fd = 0; fd < fdtablesize; fd++)
close(fd);
示例:建立一个守护进程,该进程每隔1 秒向/tmp/daemon.log写入date
示例代码:
/*************************************************************************
@Author: wanghao
@Created Time : Mon 21 May 2018 05:33:56 AMPDT
@File Name: daemon_demo.c
@Description:
************************************************************************/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#define N 128
int main()
{
FILE*fp;
pid_tpid;
inti, fd;
int line = 0;
char buf[N];
pid= fork();
if(pid < 0) {
printf("Errorfork\n");
exit(1);
}
if(pid > 0)
{
exit(0);
}
setsid();
chdir("/");
umask(0);
for(i= 0; i < getdtablesize(); i++)
{
close(i);
}
if((fp = fopen("/tmp/daemon.log", "a+")) < 0)
{
exit(1);
}
while(fgets(buf, N, fp)!= NULL)
{
line++;
}
while(1){
time_tt;
/*Getthe time as the number of seconds since the Epoch,
1970-01-01 00:00:00 +0000 (UTC).*/
time(&t);
structtm *t1;
/*Getthe current local time*/
t1=localtime(&t);
if(sprintf(buf, "%-2d %d/%d/%d %d:%d:%d\n",
++line,
t1->tm_year+1900,
t1->tm_mon+1,
t1->tm_mday,
t1->tm_hour,
t1->tm_min,
t1->tm_sec)< 0)
{
perror("fprintferror");
break;
}
printf("%s",buf);
fputs(buf,fp);
fflush(fp);
sleep(1);
}
exit(0);
}