linux基础之守护进程

一.守护进程(Daemon)
1.关于守护进程
守护进程,顾名思义,也就是专门守护一个进程的进程。守护进程的职责就是专门确保被指定的进程的运行。
守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程。它独立于控制终端,并且周期性的执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程,linux的大多数服务器就是用守护进程实现的。比如:Internet服务器inetd。Wed服务器httpd等。同时,守护进程完成了许多系统任务。比如,作业规划进程crond等。

linux系统启动时会启动很多系统服务进程,这些服务进程没有控制终端,不能和用户交互。其他进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但是系统服务进程不受用户登录注销的影响,他们一直在运行着。这种进程的名称叫做守护进程。

最直接的应用就是重启进程。如果我们的软件崩溃了,为了让软件重新运行起来,软件本身是无法不方便或者无法做到的。因为出故障就是软件本身,而这个故障严重到迫使软件本身挂掉了,自然也没有办法重启自己了。
那么可以借助一个专门的进程来帮助自己启动咯。守护进程当然不仅限于重启进程咯。要实现什么守护功能,就看你怎么实现了。你可以守护进程不被关闭,重启进程,也可以守护进程的网络,必要的配置文件等等。
守护进程好比是保镖,被守护的进程就是保镖保护的对象。守护进程在很多地方都会有应用

二.创建守护进程
1. 关于setsid函数
创建守护进程最关键一步是调用setsid函数创建一个新的Session,并成为Session Leader。

#include<unistd.h>
pid_t setsid(void);
1
2
该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。注意:调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不是进程组的Leader很容易,只要先fork再调用setsid就行了。fork的子进程和父进程在同一个进程组中,进程组的Leader必然是该进程组的第一个进程,所以子进程不可能是该组的第一个进程,所以在子进程中调用setsid是一定不会有问题的。

成功创建该函数的结果是:

创建一个新的Seccion,当前进程成为Session Leader,当前进程的id就是Session的id。
创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。
如果当前进程原本有一个控制终端,则他失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但是只是一个普通的打开文件,而不是控制终端。
查看守护进程

ps axj |grep -E 'd$'
1

TPGID一栏写着-1的都是没有控制终端的进程,也就是守护进程.
由上图可以看出1.我们上篇博客中提到的crond也为守护进程。2. 守护进程都是孤儿进程,因为其父进程的id为0;守护进程自成会话,自称进程组。

2.创建一个守护进程的流程
调用umask将文件模式创建屏蔽字设置为0;
调用fork,父进程退出(exit).原因:1.如果该守护进程是作为一个简单的shell命令启动的,那么父进程终止使得shell认为该命令已经执行完毕。2.保证子进程不是一个进程组的组长进程。
调用setsid创建一个新的会话。 setsid会导致:1 调用进程成为新会话的首进程。2 调用的进程成为进程组的组长进程。3 调用进程没有控制终端。(在此fork一次,保证daemon进程,之后不会打开tty设备)
将当前工作目录更改为根目录。
关闭不再需要的文件描述符。
其他:忽略SIGCHLD信号。
3.创建代码
#include<stdio.h>
#include<unistd.h>
#include<signal.h>

void creat_daemon()
{
umask(0);
pid_t id = fork();
if(id > 0)//father
{
return ;
}
else if(id < 0)
{
perror("fork");
return ;
}

setsid();

close(0);
close(1);
close(2);

signal(SIGCHLD,SIG_IGN);

chdir("/");
}
int main()
{
creat_daemon();
while(1)
{
sleep(1);
}
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
运行结果


4.其他
在网上我们可以看到另外一种版本是用两次fork来创建守护代码如下:

#include<stdio.h>
#include<unistd.h>
#include<signal.h>

void creat_daemon()
{

umask(0);
pid_t id = fork();
if(id > 0)//father
{
return ;
}
else if(id < 0)
{
perror("fork");
return ;
}

setsid();

signal(SIGCHLD,SIG_IGN);

if(id = fork()<0)
{
printf("fork errot\n");
return ;
}
else if(id!=0)
{
return;
}

if(chdir("/")<0)
{
printf("chdir error\n");
return ;
}
close(0);
close(1);
close(2);
}
int main()
{
creat_daemon();
while(1)
{
sleep(1);
}
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
结果如下:

原因如下:

其实现就是心跳互相检测对方是否存在,不存在就启动对方。心跳可使用socket或共享内存什么的。
如果进程比较多,可单独启动一个守护进程进行检测所有进程。守护进程比较简单,出错的可能性比较小。
再或者守护部分写到dll中,所有程序共同调用,但同时只有一个程序执行守护代码。使用内存文件映射保存信息。这样没有单独的守护进程,只要有一个进程在运行,就能保证守护代码在执行。 再或者可以考虑使用看门狗的方式。进程给一块空间定时更新数据,守护代码定时检 测数据更新时间,如果某一进程数据到一定时间超时未更新认为此进程挂掉,重启这个进程。
————————————————
版权声明:本文为CSDN博主「someday1314」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/someday1314/article/details/72942501

 

posted @ 2023-07-21 17:04  imxiangzi  阅读(449)  评论(0编辑  收藏  举报