Linux中守护进程

守护进程运行在后台,不与任何控制终端相关联。在Linux中创建一个守护进程步骤如下:
一、调用fork创建一个子进程,父进程退出,子进程归到1号进程管理,子进程将作为守护进程。子进程是由父进程创建而来,因此,它不是进程组的首进程,这是接下来调用setsid的必要条件。
二、在子进程中通过setsid,创建一个会话(新创建的会话不会分配控制终端)。当前子进程将变为新会话的首进程以及新进程组的首进程。
man手册中setsid的介绍:

 setsid()  creates  a new session if the calling process is not a process group leader.  
 The calling process is the leader of the new session, the process group leader of the new process group, and has no controlling terminal.  
The process group ID and session ID of the calling process are set to the PID of the calling process.  
The calling process will be the only process in this new process group  and  in  this new session.

三、调用chdir(),将当前工作目录改为根目录。因为守护进程是通过调用fork来创建,它继承来的当前工作目录可能在文件系统中的任何地方。而守护进程往往会在系统开机状态下一直运行,我们不希望这些随机目录一直处于打开状态,导致管理员无法卸载守护进程工作目录所在的文件系统。
四、关闭所有的文件描述符。我们不希望继承任何打开的文件描述符,不希望这些描述符一直处于打开状态而自己没有发现。
五、打开文件描述符0、1、2,并把它们重定向到/dev/null中。打开这些描述符的理由在于:守护进程调用的那些假设能从标准输入读或者往标准输出或标准错误写的库函数将不会因这些描述符未打开而失败。这种失败是一种隐患。要是一个守护进程未打开这些描述符,却作为服务器打开了与某个客户关联的一个套接字,那么这个套接字很可能占用这些描述符(譬如标准输出或标准错误输出的描述符1或2),这种情况下如果守护进程调用诸如perror之类函数,那就会把非预期的数据发送给那个客户。
代码实现:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(void) {
    pid_t pid;

    pid = fork();
    if (pid == -1) 
        return -1;
    else if (pid != 0)
        exit(EXIT_SUCCESS);

    //子进程中
    if (setsid() == -1)
        return -1;
    if (chdir("/") == -1)
        return -1;

    for (int i = 0; i < NR_OPEN; i++) {
        close(i);
    }
    
    //重定向标准输入到 /dev/null,因为此时open返回的fd 是 0,以下同理
    open("/dev/null", O_RDONLY);
    open("/dev/null", O_RDWR);
    open("/dev/null", O_RDWR);

    return 0;
}

这时该程序便可以在后台运行了(如果是服务端程序通常都会处在一个loop中)

其实,更简单一点,我们可以直接使用daemon系统调用

#include 

int daemon(int nochdir, int noclose);

man手册:

The daemon() function is for programs wishing to detach themselves from the controlling terminal and run in the background as system daemons.

If nochdir is zero, daemon() changes the calling process's current working directory to the root directory ("/"); otherwise, the current working directory is left unchanged.

If noclose is zero, daemon() redirects standard input, standard output and standard error to /dev/null; otherwise, no changes are made to these file descriptors.

如果参数nochdir为0,就会将该进程的工作目录改变到根目录,如果参数noclose为0,就会将标准输入、标准输出、标准错误重定位到/dev/null。因此,两个参数一般都设置为0。

你可能感兴趣的:(Linux后端,linux,服务器,运维,守护进程)