守护进程

12 篇文章 0 订阅

守护进程是在后台运行并且没有控制终端的进程。

由于守护进程通常没有控制终端,所以,几乎不需要与用户交互。守护进程用于提供哪些没有任何用户交互就可以在后台做得很好的服务。

例如,一个在后台运行观察网络活动并且记录任何可疑通信日志的进程就可以开发成守护进程。

守护进程设计开发守护进程就像开发其他进程一样,但有一件事情即没有控制终端使它与任何其他普通进程区别开来。这就是创建守护进程时的主要设计问题。这可以通过以下步骤实现:
  • 创建一个普通进程(父进程)
  • 从上述父进程内部创建一个子进程
  • 在这个时候,进程的层次关系看起来像:终端 à 父进程 à 子进程
  • 终止父进程
  • 子进程现在成为孤儿然后被init进程收养
  • 在新会话中调用setsid()函数运行这个进程并拥有一个新的用户组
  • 经过以上步骤之后,可以说现在这个进程成为没有控制终端的守护进程
  • 将守护进程的工作目录改为根目录,然后关闭stdin、stdout和stderr文件描述符
  • 让守护进程的主逻辑运行
因此,我们看到,以上步骤为创建守护进程指明了基本设计步骤。C语言fork()函数

按以上所述的设计步骤创建可实际运行的守护进程之前,让我们首先了解一点fork()系统调用的知识。

fork()系统调用创建的进程是一个与父进程完全一样的复制品。这个新进程被称为‘子’进程。

这个系统调用(在父进程中)被调用一次,但返回两次(一次返回父进程,第二次返回子进程)。注意,在fork()系统调用之后,是父进程还是子进程先运行是不确定的。它完全依赖于上下文切换机制。这个调用在子进程中返回0而在父进程中返回子进程的PID。

这个系统调用的一些重要方面如下:

  • 子进程拥有属于自己的惟一的进程ID,而且这一PID与现存任何进程组ID不一致。
  • 子进程的父进程ID与父进程的进程ID相同。
  • 子进程没有继承其父进程的内存锁。
  • 子进程中的进程资源使用和CPU时间计数器重置为0。
  • 子进程挂起信号集初始化为空。
  • 子进程不继承父进程的信号量调节值。
  • 子进程不继承父进程的记录锁。
  • 子进程不继承父进程的定时器。
  • 子进程不继承父进程未完成的异步I/O操作,也不继承父进程的任何异步I/O上下文。
想要更多信息,请阅读这个系统调用的手册页。


A daemon process is a process which runs in background and has no controlling terminal.

Since a daemon process usually has no controlling terminal so almost no user interaction is required. Daemon processes are used to provide services that can well be done in background without any user interaction.

For example a process that runs in background and observes network activity and logs any suspicious communication can be developed as a daemon process.

Daemon Process Design

A daemon process can be developed just like any other process but there is one thing that differentiates it with any other normal process ie having no controlling terminal. This is a major design aspect in creating a daemon process. This can be achieved by :

  • Create a normal process (Parent process)
  • Create a child process from within the above parent process
  • The process hierarchy at this stage looks like :  TERMINAL -> PARENT PROCESS -> CHILD PROCESS
  • Terminate the the parent process.
  • The child process now becomes orphan and is taken over by the init process.
  • Call setsid() function to run the process in new session and have a new group.
  • After the above step we can say that now this process becomes a daemon process without having a controlling terminal.
  • Change the working directory of the daemon process to root and close stdin, stdout and stderr file descriptors.
  • Let the main logic of daemon process run.

So we see that above steps mark basic design steps for creating a daemon.

C fork() Function

Before creating an actual running daemon following the above stated design steps, lets first learn a bit about the fork() system call.

fork() system creates a child process that is exact replica of the parent process. This new process is referred as ‘child’ process.

This system call gets called once (in parent process) but returns twice (once in parent and second time in child). Note that after the fork() system call, whether the parent will run first or the child is non-deterministic. It purely depends on the context switch mechanism. This call returns zero in child while returns PID of child process in the parent process.

Following are some important aspects of this call :

  • The child has its own unique process ID, and this PID does not match the ID of any existing process group.
  • The child’s parent process ID is the same as the parent’s process ID.
  • The child does not inherit its parent’s memory locks.
  • Process resource utilization and CPU time counters are reset to zero in the child.
  • The child’s set of pending signals is initially empty.
  • The child does not inherit semaphore adjustments from its parent.
  • The child does not inherit record locks from its parent.
  • The child does not inherit timers from its parent.
  • The child does not inherit outstanding asynchronous I/O operations from its parent, nor does it inherit  any  asynchronous I/O contexts from its parent.

For more insight information, please read the man page of this system call.

The Implementation

Based on the design as mentioned in the first section. Here is the complete implementation :

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <string.h>

int main(int argc, char* argv[])

{

FILE *fp= NULL;

pid_t process_id = 0;

pid_t sid = 0;

// Create child process

process_id = fork();

// Indication of fork() failure

if (process_id < 0)

{

printf("fork failed!\n");

// Return failure in exit status

exit(1);

}

// PARENT PROCESS. Need to kill it.

if (process_id > 0)

{

printf("process_id of child process %d \n",process_id);

// return success in exit status

exit(0);

}

//unmask the file mode

umask(0);

//set new session

sid = setsid();

if(sid < 0)

{

// Return failure

exit(1);

}

// Change the current working directory to root.

chdir("/");

// Close stdin. stdout and stderr

close(STDIN_FILENO);

close(STDOUT_FILENO);

close(STDERR_FILENO);

// Open a log file in write mode.

fp = fopen ("Log.txt", "w+");

while (1)

{

//Dont block context switches, let the process sleep forsome time

sleep(1);

fprintf(fp, "Logging info...\n");

fflush(fp);

// Implement and call some function that does core workfor this daemon.

}

fclose(fp);

return (0);

}

 

 

Following is the way through which the code was compiled and executed:

$ gcc -Wall deamon.c -o deamon$ sudo ./deamonprocess_id of child process 2936

Just observe that the control immediately came back to the terminal ie the daemon is now not associated to any terminal.

When you check the log.txt file located in the root directory, you could see that this daemon process is running.

$

$ tail -f /Log.txt

Logging info...

Logging info...

Logging info...

Logging info...

Logging info...

Logging info...

Logging info...

Logging info...

Logging info...

Logging info...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值