会话用来管理前后台进程组。
会话一般关联着一个终端。
关闭一个终端,它对应的会话中的所有进程都会被关闭。
守护进程
不受终端影响,就算终端退出,也可以继续在后台运行。
如何写一个守护进程
- 1、创建一个子进程,让父进程直接而退出(避免父进程一直占有终端的使用权,那样shell才有终端的使用权限)。
可以通过fork() 函数。 - 2、创建一个新的会话,子进程需要在一个新的会话里面,那样才不受当前终端影响,摆脱当前终端。
通过setsid()函数 - 3、改变守护进程的当前工作目录,改为“ / ”,当父进程使用fork() 函数生成子进程时,子进程的当前工作目录就是这个父进程的工作目录。
通过chrdir() 函数来实现 - 4、重设文件权限掩码,新建文件的权限收到文件权限掩码的影响,可以使用 shell指令 “ umask ”来查看文件权限掩码的值。结果0022 表示只写,当前用户,用户组的,其他用户的。新建默认是666,与umask的掩码值进行与(~umask码),得到最终的644。
通过umask()函数可以直接重设umask值。 - 5、关闭不需要的文件描述符。0,1,2:标准输入,标准输出,标准出错。这三都是直接和终端相关联的。因为希望守护进程完全脱离终端的影响。通过close()关闭这三个文件描述符即可。
测试程序
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/stat.h>
#define MAXFILE 3
int main()
{
pid_t pid;
int fd,len,i,num;
char *buf = "The daemon is running.\n";
len = strlen(buf) + 1;
//创建子进程,销毁父进程
pid = fork();
if(pid < 0)
{
puts("fork fail");
exit(1);
}
if(pid > 0)
{
exit(0);
}
//创建新会话,摆脱终端的影响
setsid();
//改变当前工作目录
chdir("/");
//重设文件权限掩码
umask(0);
//关闭文件的默认描述符
for(i=0;i<MAXFILE;i++)
{
close(i);
}
//实现守护进程的功能
while(1)
{
//fd = open("./daemon.log",O_CREAT | O_WRONLY | O_APPEND,0666);
//我一开始用上面这个相对目录,似乎无法创建文件,
//改成下面的绝对路径文件创建、写成功。
fd = open("/home/jl/test/daemon.log",O_CREAT | O_WRONLY | O_APPEND,0666);
write(fd,buf,len);
close(fd);
sleep(5);
}
}
实验结果
关闭当前终端,打开一个新的终端
jl@jl-virtual-machine:~/test$ ls
a.out dae.c daemon.log dsadsa.c epit exit.c fscanf.c precise stack.c test tt1.c tt.c wait.c
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$ ps aux | grep a.out
jl 15237 0.0 0.0 4380 72 ? Ss 00:15 0:00 ./a.out
jl 15432 0.0 0.0 16180 1064 pts/0 R+ 00:17 0:00 grep --color=auto a.out
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$ cat daemon.log
The daemon is running.
The daemon is running.
The daemon is running.
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$
jl@jl-virtual-machine:~/test$ cat daemon.log
The daemon is running.
The daemon is running.
The daemon is running.
The daemon is running.
The daemon is running.
The daemon is running.
The daemon is running.
The daemon is running.
The daemon is running.
jl@jl-virtual-machine:~/test$
可以看到log文件成功产生,该进程依然存在,并且不断地往log文件里面写log。
测试成功!
普通进程伪装成守护进程(不是真正的,有细微的差别):
shell指令 “ nohub ”
nohub sleep 1000 &
关闭当前终端,在另一个终端里面使用
ps aux | grep sleep
发现该进程依然存在。