在 Linux 中创建守护进程 [英] Creating a daemon in Linux

查看:40
本文介绍了在 Linux 中创建守护进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Linux 中,我想添加一个无法停止并监视文件系统更改的守护程序.如果检测到任何更改,它应该将路径写入控制台的启动位置,并添加一个换行符.

我已经准备好文件系统更改代码,但我不知道如何创建守护进程.

我的代码来自这里:http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

分叉后怎么办?

int main (int argc, char **argv) {pid_t pID = fork();if (pID == 0) {//孩子//代码仅由子进程执行sIdentifier = "子进程:";}否则如果 (pID <0) {cerr<<分叉失败"<<结束;退出(1);//抛出异常}else//父级{//代码仅由父进程执行sIdentifier = "父进程:";}返回0;}

解决方案

在 Linux 中,我想添加一个无法停止并监视文件系统更改的守护程序.如果检测到任何更改,则应将路径写入控制台的起始位置 + 换行符.

守护进程在后台工作并且(通常...)不属于 TTY,这就是为什么您不能以您可能想要的方式使用 stdout/stderr.通常,系统日志守护进程 (syslogd) 用于将消息记录到文件(调试、错误等).

除此之外,还有一些必需的步骤来守护进程.

<小时>

如果我没记错的话,这些步骤是:

  • fork 父进程&如果分叉成功,让它终止.-> 因为父进程已经终止,子进程现在在后台运行.
  • setsid - 创建一个新会话.调用进程成为新会话的领导者和新进程组的进程组领导.该进程现在与其控制终端 (CTTY) 分离.
  • 捕捉信号 - 忽略和/或处理信号.
  • 再次分叉 &让父进程终止以确保您摆脱会话引导进程.(只有会话负责人可以再次获得 TTY.)
  • chdir - 更改守护进程的工作目录.
  • umask - 根据守护进程的需要更改文件模式掩码.
  • close - 关闭所有可能从父进程继承的打开的文件描述符.
<小时>

给你一个起点:看看这个显示基本步骤的骨架代码.此代码现在也可以在 GitHub 上分叉:Linux 守护进程的基本框架

/** daemonize.c* 此示例守护进程,写入一些日志消息,* 休眠 20 秒,然后终止.*/#include #include #include #include #include #include #include 静态无效 skeleton_daemon(){pid_t pid;/* 分叉出父进程 */pid = fork();/* 发生错误 */如果 (pid <0)退出(EXIT_FAILURE);/* 成功:让父进程终止 */如果(pid > 0)退出(退出成功);/* 成功时:子进程成为会话领导 */如果 (setsid() <0)退出(EXIT_FAILURE);/* 捕捉、忽略和处理信号 *///TODO: 实现一个工作信号处理程序 */信号(SIGCHLD,SIG_IGN);信号(SIGHUP,SIG_IGN);/* 第二次分叉*/pid = fork();/* 发生错误 */如果 (pid <0)退出(EXIT_FAILURE);/* 成功:让父进程终止 */如果(pid > 0)退出(退出成功);/* 设置新文件权限 */umask(0);/* 将工作目录更改为根目录 *//* 或其他合适的目录 */chdir("/");/* 关闭所有打开的文件描述符 */整数 x;for (x = sysconf(_SC_OPEN_MAX); x>=0; x--){关闭 (x);}/* 打开日志文件 */openlog ("firstdaemon", LOG_PID, LOG_DAEMON);}

int main(){骨架守护程序();而 (1){//TODO: 在此处插入守护程序代码.系统日志(LOG_NOTICE,第一个守护进程已启动.");睡觉 (20);休息;}系统日志(LOG_NOTICE,第一个守护进程终止.");关闭日志();返回退出成功;}


  • 编译代码:gcc -o firstdaemon daemonize.c
  • 启动守护进程:./firstdaemon
  • 检查是否一切正常:ps -xj |grep firstdaemon

  • 输出应该类似于这个:

<前>+------+------+------+------+-------+-------+------+------+------+-----+|PPID |PID |PGID |SID |打字电话 |TPGID |统计 |用户名|时间 |CMD |+------+------+------+------+-------+-------+------+------+------+-----+|1 |3387 |3386 |3386 |?|-1 || |1000 |0:00 |./|+------+------+------+------+-------+-------+------+------+------+-----+

您应该在这里看到的是:

  • 守护进程没有控制终端 (TTY = ?)
  • 父进程 ID (PPID) 是 1(init 进程)
  • PID != SID 这意味着我们的进程不是会话领导者
    (因为第二个 fork())
  • 因为 PID != SID 我们的进程无法再次控制 TTY

读取系统日志:

  • 找到您的系统日志文件.我的在这里:/var/log/syslog
  • 做一个:grep firstdaemon/var/log/syslog

  • 输出应该类似于这个:

<前>firstdaemon[3387]:第一个守护进程启动.firstdaemon[3387]:第一个守护进程终止.


注意事项:实际上,您还需要实现一个信号处理程序并正确设置日志记录(文件、日志级别...).

进一步阅读:

In Linux I want to add a daemon that cannot be stopped and which monitors filesystem changes. If any changes are detected, it should write the path to the console where it was started plus a newline.

I already have the filesystem changing code almost ready but I cannot figure out how to create a daemon.

My code is from here: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

What to do after the fork?

int main (int argc, char **argv) {

  pid_t pID = fork();
  if (pID == 0)  {              // child
          // Code only executed by child process    
      sIdentifier = "Child Process: ";
    }
    else if (pID < 0) {
        cerr << "Failed to fork" << endl;
        exit(1);
       // Throw exception
    }
    else                                   // parent
    {
      // Code only executed by parent process

      sIdentifier = "Parent Process:";
    }       

    return 0;
}

解决方案

In Linux i want to add a daemon that cannot be stopped and which monitors filesystem changes. If any changes would be detected it should write the path to the console where it was started + a newline.

Daemons work in the background and (usually...) don't belong to a TTY that's why you can't use stdout/stderr in the way you probably want. Usually a syslog daemon (syslogd) is used for logging messages to files (debug, error,...).

Besides that, there are a few required steps to daemonize a process.


If I remember correctly these steps are:

  • fork off the parent process & let it terminate if forking was successful. -> Because the parent process has terminated, the child process now runs in the background.
  • setsid - Create a new session. The calling process becomes the leader of the new session and the process group leader of the new process group. The process is now detached from its controlling terminal (CTTY).
  • Catch signals - Ignore and/or handle signals.
  • fork again & let the parent process terminate to ensure that you get rid of the session leading process. (Only session leaders may get a TTY again.)
  • chdir - Change the working directory of the daemon.
  • umask - Change the file mode mask according to the needs of the daemon.
  • close - Close all open file descriptors that may be inherited from the parent process.

To give you a starting point: Look at this skeleton code that shows the basic steps. This code can now also be forked on GitHub: Basic skeleton of a linux daemon

/*
 * daemonize.c
 * This example daemonizes a process, writes a few log messages,
 * sleeps 20 seconds and terminates afterwards.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>

static void skeleton_daemon()
{
    pid_t pid;

    /* Fork off the parent process */
    pid = fork();

    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);

    /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);

    /* On success: The child process becomes session leader */
    if (setsid() < 0)
        exit(EXIT_FAILURE);

    /* Catch, ignore and handle signals */
    //TODO: Implement a working signal handler */
    signal(SIGCHLD, SIG_IGN);
    signal(SIGHUP, SIG_IGN);

    /* Fork off for the second time*/
    pid = fork();

    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);

    /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);

    /* Set new file permissions */
    umask(0);

    /* Change the working directory to the root directory */
    /* or another appropriated directory */
    chdir("/");

    /* Close all open file descriptors */
    int x;
    for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
    {
        close (x);
    }

    /* Open the log file */
    openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
}

int main()
{
    skeleton_daemon();

    while (1)
    {
        //TODO: Insert daemon code here.
        syslog (LOG_NOTICE, "First daemon started.");
        sleep (20);
        break;
    }

    syslog (LOG_NOTICE, "First daemon terminated.");
    closelog();

    return EXIT_SUCCESS;
}


  • Compile the code: gcc -o firstdaemon daemonize.c
  • Start the daemon: ./firstdaemon
  • Check if everything is working properly: ps -xj | grep firstdaemon

  • The output should be similar to this one:

+------+------+------+------+-----+-------+------+------+------+-----+
| PPID | PID  | PGID | SID  | TTY | TPGID | STAT | UID  | TIME | CMD |
+------+------+------+------+-----+-------+------+------+------+-----+
|    1 | 3387 | 3386 | 3386 | ?   |    -1 | S    | 1000 | 0:00 | ./  |
+------+------+------+------+-----+-------+------+------+------+-----+

What you should see here is:

  • The daemon has no controlling terminal (TTY = ?)
  • The parent process ID (PPID) is 1 (The init process)
  • The PID != SID which means that our process is NOT the session leader
    (because of the second fork())
  • Because PID != SID our process can't take control of a TTY again

Reading the syslog:

  • Locate your syslog file. Mine is here: /var/log/syslog
  • Do a: grep firstdaemon /var/log/syslog

  • The output should be similar to this one:

  firstdaemon[3387]: First daemon started.
  firstdaemon[3387]: First daemon terminated.


A note: In reality you would also want to implement a signal handler and set up the logging properly (Files, log levels...).

Further reading:

这篇关于在 Linux 中创建守护进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆