守护进程
如果一个进程永远都是以后台方式启动,并且不能受到Shell退出影响而退出,一个正统的做法是将其创建为守护进程。守护进程值得是系统长期运行的后台进程,类似Windows服务。守护进程信息通过ps –a无法查看到,需要用到–x参数,当使用这条命令的时候,往往还附上-j参数以查看作业控制信息,其中TPGID一栏为-1就是守护进程
创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。成功调用该函数的结果是:
-
创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id
-
创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id
-
如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。
三. 守护进程实例
例程:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#define LOG_FILE "/tmp/my.log"
int Daemon(int nochdir, int noclose)
{
/*1. 调用fork,创建子进程,并退出父进程*/
pid_t p = fork();
if (p == -1) {
perror("fork failed");
return -1;
}
if (p > 0) {
_exit(0);
}
/*1000微妙*/
usleep(1000);
/*2. 脱离终端,成为会话组的组长,主进程*/
p = setsid();
if (p == -1) {
perror("setsid failed.");
return -1;
}
/*3. 改变家目录为根目录*/
if (! nochdir) {
chdir("/");
}
/*4. 关闭所有打开过的文件*/
if (! noclose) {
int dtable_size = getdtablesize();//返回每个进程所能打开的最大的文件数量
for (;dtable_size >= 0; --dtable_size) {
close(dtable_size);
}
}
/*5.把输出重定向到日志文件中*/
int null_fd = open("/dev/null", O_RDWR);
dup2(null_fd, STDIN_FILENO);//输入为NULL
int log_fd = open(LOG_FILE, O_WRONLY | O_APPEND| O_CREAT, 0666);
if (log_fd != -1) {
dup2(log_fd, STDOUT_FILENO);
//dup2(log_fd, STDERR_FILENO);
}
return 0;
}
int main()
{
printf("pid = %d, ppid = %d\n", getpid(), getppid());
Daemon(0, 0);
while (1) {
printf("daemon is running, %d, %d\n", getpid(), getppid());
sleep(1);
}
return 0;
}