概念:
守护进程又叫精灵进程(Daemon Process),是linux三种进程之一,是linux中的后台服务进程,它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
进程组(Process Group): 进程集合,每个进程组有一个组长(Leader),其进程 ID 就是该进程组 ID。进程fork一个子进程,此父进程和子进程就是一个进程组,父进程就是进程组组长;
会话(Session):进程组集合,每个会话有一个组长,其进程 ID 就是该会话组 ID。
控制终端(Controlling Terminal):每个会话可以有一个单独的控制终端,与控制终端连接的 Leader 就是控制进程(Controlling Process)。
控制终端是会话的载体;
会话==终端;
特点:
始终在后台运行,独立于任何终端,周期性的执行某种任务或等待处理特定事件。
它是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。
举例:
http 服务的守护进程叫 httpd,mysql 服务的守护进程叫 mysqld。
更简便地创建守护进程:
nohup 命令
nohup xxxx &//将进程直接转入后台(不推荐用,少步骤)
守护进程创建:
守护进程创建第一步:
1.创建子进程,父进程退出
2.子进程会变成孤儿进程
孤儿进程,不一定会被1号init进程回收,是因为init进程要管理的事情太多了,现在像回收子进程这些事情他就不会自己做了,他会去创建一些其他进程去给回收子进程的资源
3.子进程在后台运行
相关函数:
1. pid_t fork(void);//为当前进程创建子进程
函数返回值:为父进程返回子进程pid,为子进程返回0
2.exit(data);//结束当前进程
返回(data)
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(){
pid_t pid;
pid=fork();
if(pid<0){
perror("fork");
return -1;
}else if(pid==0){
printf("son is born\n");
sleep(10);//程序运行完进程结束,为了方便观察进程,让进程睡一会
}else
exit(0);
}
守护进程创建第二步:
子进程创建新会话
子进程成为新的会话组长,和新的进程组组长
子进程脱离原来的终端
相关函数:
#include <unistd.h>
1. pid_t setsid(void);
成功:返回调用进程的会话ID;失败:-1,设置errno。
调用了setsid函数的进程,既是新的会长,也是新的组长
2. pid_t getsid(pid_t pid)
成功:返回调用进程的会话ID;失败:-1,设置errno
:pid为0表示察看当前进程session ID
:ps ajx命令查看系统中的进程。参数a表示不仅列当前用户的进程,也列出所有其他用户的进程,参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程,参数j表示列出与作业控制相关的信息。
:组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程。
3. getpid:pid_t getpid(void); 获取进程id
4. getpgid:pid_t getpgid(pid_t pid); 获取进程组id
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/stat.h>
int main(){
pid_t pid;
pid=fork();
if(pid<0){
perror("fork");
return -1;
}else if(pid>0){
exit(0);
}
printf("this is san\n");
printf("before:getsid=%d %d %d\n",getsid(getpid()),getpid(),getpgid(getpid()));
if(setsid()<0){
perror("setsid");
exit(0);
}
printf("after:getsid=%d %d %d\n",getsid(getpid()),getpid(),getpgid(getpid()));
子进程创建第三步:(不必须)
改变工作目录
因为守护进程一直在后台工作,其工作目录不能被删除,需要稳定的工作目录
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/stat.h>
int main(){
pid_t pid;
pid=fork();
if(pid<0){
perror("fork");
return -1;
}else if(pid>0){
exit(0);
}
printf("this is san\n");
printf("before:getsid=%d %d %d\n",getsid(getpid()),getpid(),getpgid(getpid()));
if(setsid()<0){
perror("setsid");
exit(0);
}
printf("after:getsid=%d %d %d\n",getsid(getpid()),getpid(),getpgid(getpid()));
chdir("/");
子进程创建第四步:
重设文件权限掩码
使用umask创建文件权限不会被系统权限所影响;
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/stat.h>
int main(){
pid_t pid;
pid=fork();
if(pid<0){
perror("fork");
return -1;
}else if(pid>0){
exit(0);
}
printf("this is san\n");
printf("before:getsid=%d %d %d\n",getsid(getpid()),getpid(),getpgid(getpid()));
if(setsid()<0){
perror("setsid");
exit(0);
}
printf("after:getsid=%d %d %d\n",getsid(getpid()),getpid(),getpgid(getpid()));
chdir("/");
if(umask(0)<0){
perror("unask");
return -1;
}
子进程创建第五步:
关闭打开的文件描述符
因为守护进程脱离终端,标准输入输出,标准错误不能再使用。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/stat.h>
int main(){
pid_t pid;
pid=fork();
if(pid<0){
perror("fork");
return -1;
}else if(pid>0){
exit(0);
}
printf("this is san\n");
printf("before:getsid=%d %d %d\n",getsid(getpid()),getpid(),getpgid(getpid()));
if(setsid()<0){
perror("setsid");
exit(0);
}
printf("after:getsid=%d %d %d\n",getsid(getpid()),getpid(),getpgid(getpid()));
chdir("/");
if(umask(0)<0){
perror("unask");
return -1;
}
close(0);
slose(1);
close(2);
sleep(100);
return 0;
}
其它相关命令:
ps -elf|grep +执行进程文件//查看进程信息
在Linux系统中,ps
命令用于列出系统中的进程信息。命令格式为:
ps [options]
ps
命令可以显示当前用户的进程、系统所有进程、以及其他用户的进程等信息。常用的选项包括:
a
:显示所有进程u
:显示更详细的进程信息x
:显示无控制终端的进程aux
:显示所有进程的详细信息,包括其他用户的进程e
:显示环境变量f
:显示进程的树形结构
在Linux系统中,kill
命令用于终止指定进程的执行。命令格式为:
kill [signal] [PID]
其中,signal
表示要发送给进程的信号,可以是信号名称或信号编号。常用的信号包括:
1
(SIGHUP):挂起信号9
(SIGKILL):强制终止信号15
(SIGTERM):终止信号
PID
表示要终止的进程的进程号。