(一)守护进程的特点
进程运行起来除了拥有可执行文件加载到内存上之外,还需要操作系统分配进程控制块、CPU寄存器、堆栈。守护进程通常在系统启动时运行,系统结束时关闭。很多服务器都是守护进程运行。
(1)始终在后台运行:守护进程不占用终端,和终端无关,一直在后台运行,随linux操作系统终止而终止,无法手动关闭。
(2)独立于任何的终端。
(3)周期性的执行某种任务或者等待处理特定的事件。
注:守护进程属于后台进程,但是jobs只能查看当前终端下的后台进程,而守护进程和终端无关,因此jobs无法查看守护进程。
(二)系统调用和库
系统调用:由linux内核提供的函数
库函数:存放在函数库中的函数。库函数具有明确的功能、入口调用参数和返回值。一般封装系统调用函数提供对外的API。
(三)fork(系统调用)
#include <unistd.h>
pid_t fork(void);
(1)子进程是从fork后面开始执行,即紧接着是return返回值。
(2)fork();生成两个进程:父进程和子进程。父子进程运行时,相互独立,互不影响,并发运行;究竟是父进程先于子进程执行,还是子进程先于父进程执行,这取决于内核的系统调度。
(3)父进程的ppid是/bin/bash
(四)守护进程-会话、控制终端
linux以会话session、进程组的方式管理进程,每个进程属于一个进程组。
(1)会话
会话是一个或者多个进程组的集合。通常用户打开一个终端时,系统会创建一个会话,所有通过该终端运行的进程都属于这个会话。
终端关闭时,所有相关的进程都会结束。
(五)守护进程的创建
(1)创建子进程,父进程退出;让子进程变成孤儿进程,被init进程收养,使子进程在后台运行。
if(fork() > 0)
{
exit(0);
}
(2)setsid子进程创建新的会话
a.子进程成为新的会话组长
b.子进程脱离原先的终端
#include <unistd.h>
pid_t setsid(void);
if(setsid() < 0)
{
exit(-1);
}
(3)chdir更改当前的工作目录
更改为稳定的不会被卸载删除的目录
#include <unistd.h>
int chdir(const char *path); //相当于cd命令
(4)umask重新设置文件权限掩码
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);
eg:
if(umask(0) < 0)
{
exit(-1);
}
(5)关闭从父进程继承而来的文件描述符
关闭从父进程继承而来的文件描述符,
已脱离终端,stdin,stdout,stderr无法再使用。
int i;
for(i = 0; i < getdtablesize(); i++) // i < 3
{
close(i);
}
程序如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6
7
8 int main(int argc, const char *argv[])
9 {
10 int i;
11 pid_t pid;
12
13 pid = fork();
14 if(pid < 0)
15 {
16 perror("fork error");
17 exit(-1);
18 }
19
20 if(pid > 0)
21 {
22 exit(0);
23 }
24
25 if(setsid() < 0)
26 {
27 exit(-1);
28 }
29
30 chdir("./");
31
32 if(umask(0) < 0)
33 {
34 exit(-1);
35 }
36
37 for(i = 0; i < getdtablesize(); i++)
38 {
39 //close(i);
40 }
41 printf("setsid successs\n");
42
43 while(1)
44 {
45 sleep(1);
46 }
47
48 return 0;
49 }
~
(六)daemon函数
daemon(0, 0); //函数自动生成守护进程
NAME
daemon - run in the background
SYNOPSIS
#include <unistd.h>
int daemon(int nochdir, int noclose);