当前位置: 首页 > 知识库问答 >
问题:

在Linux中创建守护进程

马凡
2023-03-14

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

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

我的密码是:http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

叉子用完后怎么办?

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;
}

共有3个答案

解念
2023-03-14

不能在linux中创建无法终止的进程。根用户(uid=0)可以向进程发送信号,有两个信号无法捕获,SIGKILL=9,SIGSTOP=19。和其他信号(未捕获时)也可能导致进程终止。

您可能需要一个更通用的守护程序函数,在该函数中,您可以为您的程序/守护程序指定名称,以及运行程序的路径(可能是/或/tmp)。您可能还需要为stderr和stdout(可能还有使用stdin的控制路径)提供文件。

以下是必要的包括:

#include <stdio.h>    //printf(3)
#include <stdlib.h>   //exit(3)
#include <unistd.h>   //fork(3), chdir(3), sysconf(3)
#include <signal.h>   //signal(3)
#include <sys/stat.h> //umask(3)
#include <syslog.h>   //syslog(3), openlog(3), closelog(3)

这是一个更一般的函数,

int
daemonize(char* name, char* path, char* outfile, char* errfile, char* infile )
{
    if(!path) { path="/"; }
    if(!name) { name="medaemon"; }
    if(!infile) { infile="/dev/null"; }
    if(!outfile) { outfile="/dev/null"; }
    if(!errfile) { errfile="/dev/null"; }
    //printf("%s %s %s %s\n",name,path,outfile,infile);
    pid_t child;
    //fork, detach from process group leader
    if( (child=fork())<0 ) { //failed fork
        fprintf(stderr,"error: failed fork\n");
        exit(EXIT_FAILURE);
    }
    if (child>0) { //parent
        exit(EXIT_SUCCESS);
    }
    if( setsid()<0 ) { //failed to become session leader
        fprintf(stderr,"error: failed setsid\n");
        exit(EXIT_FAILURE);
    }

    //catch/ignore signals
    signal(SIGCHLD,SIG_IGN);
    signal(SIGHUP,SIG_IGN);

    //fork second time
    if ( (child=fork())<0) { //failed fork
        fprintf(stderr,"error: failed fork\n");
        exit(EXIT_FAILURE);
    }
    if( child>0 ) { //parent
        exit(EXIT_SUCCESS);
    }

    //new file permissions
    umask(0);
    //change to path directory
    chdir(path);

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

    //reopen stdin, stdout, stderr
    stdin=fopen(infile,"r");   //fd=0
    stdout=fopen(outfile,"w+");  //fd=1
    stderr=fopen(errfile,"w+");  //fd=2

    //open syslog
    openlog(name,LOG_PID,LOG_DAEMON);
    return(0);
}

下面是一个示例程序,它成为一个守护进程,挂起,然后离开。

int
main()
{
    int res;
    int ttl=120;
    int delay=5;
    if( (res=daemonize("mydaemon","/tmp",NULL,NULL,NULL)) != 0 ) {
        fprintf(stderr,"error: daemonize failed\n");
        exit(EXIT_FAILURE);
    }
    while( ttl>0 ) {
        //daemon code here
        syslog(LOG_NOTICE,"daemon ttl %d",ttl);
        sleep(delay);
        ttl-=delay;
    }
    syslog(LOG_NOTICE,"daemon ttl expired");
    closelog();
    return(EXIT_SUCCESS);
}

注意,SIG_IGN表示捕捉并忽略信号。您可以构建一个可以记录信号接收的信号处理程序,并设置标志(例如指示正常关机的标志)。

冀望
2023-03-14

man 7 daemon详细介绍了如何创建daemon。我的答案只是摘录自本手册。

至少有两种类型的守护程序:

  1. 传统的SysV守护进程(旧式),
  2. systemd守护进程(新型)

如果您对传统的SysV守护进程感兴趣,则应实现以下步骤:

  1. 关闭所有打开的文件描述符(标准输入、输出和错误除外)(即前三个文件描述符0、1、2)。这可以确保没有意外传递的文件描述符留在守护进程中。在Linux上,这最好通过迭代/proc/self/fd来实现,回退是从文件描述符3迭代到RLIMIT\u NOFILEgetrlimit()返回的值

请注意以下警告:

不应该使用BSDdaemon()函数,因为它只实现了这些步骤的子集。

需要提供与SysV系统兼容性的守护进程应该实现上述方案。但是,建议通过命令行参数使这种行为成为可选的和可配置的,以便于调试,并简化使用system d集成到系统中的过程

请注意,daemon()与POSIX不兼容。

对于新型守护进程,建议执行以下步骤:

  1. 如果收到SIGTERM,请关闭守护进程并干净地退出
  2. 如果收到SIGHUP,则重新加载配置文件(如果适用)
  3. 提供主守护进程的正确退出代码,因为init系统使用该代码检测服务错误和问题。建议遵循针对SysV init脚本的LSB建议中定义的退出代码方案
  4. 如果可能且适用,通过D-Bus IPC系统公开守护进程的控制接口,并获取总线名称作为初始化的最后一步
  5. 对于systemd中的集成,请提供一个。服务单元文件,其中包含有关启动、停止和以其他方式维护守护进程的信息。参见systemd。服务(5)了解详细信息
  6. 尽可能地依赖init系统的功能来限制守护进程对文件、服务和其他资源的访问,即在systemd的情况下,依赖systemd的资源限制控制而不是实现您自己的控制,依赖systemd的特权删除代码而不是在守护进程中实现它,等等。参见systemd。exec(5),查看可用控件
  7. 如果使用了D-Bus,请通过提供D-Bus服务激活配置文件来激活守护程序总线。这有多个优点:您的守护进程可以根据需要延迟启动;它可以与其他需要它的守护进程并行启动,从而最大限度地提高并行化和启动速度;您的守护进程可以在出现故障时重新启动,而不会丢失任何总线请求,因为总线会对可激活服务的请求进行排队。详情见下文
  8. 如果您的守护进程通过套接字向其他本地进程或远程客户端提供服务,则应按照下面指出的方案使其可激活套接字。与D-Bus激活一样,这支持按需启动服务,并允许改进服务启动的并行化。此外,对于无状态协议(如syslog、DNS),实现基于套接字的激活的守护进程可以在不丢失单个请求的情况下重新启动。详情见下文
  9. 如果适用,守护进程应通过sd\u notify(3)接口通知init系统启动完成或状态更新
  10. 新样式的守护进程可以选择通过fprintf()直接记录到标准错误,而不是使用syslog()调用直接记录到系统syslog服务,然后由init系统转发到syslog。如果日志级别是必需的,可以通过在单个日志行前面加上字符串(如“0”)对其进行编码

要了解更多信息,请阅读全文man7守护进程

翟元凯
2023-03-14

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

守护进程在后台工作(通常...)不属于TTY,这就是为什么你不能以你可能想要的方式使用stdout/stderr。通常使用syslog守护进程(syromd)将消息记录到文件中(debug,错误,...)。

除此之外,还需要几个步骤来对流程进行后台监控

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

  • 离开父进程

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

/*
 * 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;
}

>

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

    输出应类似于此:

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

    您应该在这里看到:

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

    正在读取系统日志:

    >

    输出应类似于此:

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


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

    进一步阅读:

    • Linux-UNIX-编程-德语
    • Unix守护服务器编程

  •  类似资料:
    • 问题内容: 在Linux中,我想添加一个无法停止且监视文件系统更改的守护程序。如果检测到任何更改,则应在启动控制台的路径上加上换行符。 我已经准备好更改代码的文件系统了,但是我不知道如何创建守护程序。 我的代码来自这里:http : //www.yolinux.com/TUTORIALS/ForkExecProcesses.html 叉后该怎么办? 问题答案: 在Linux中,我想添加一个无法停止

    • 问题内容: 我正在编写Linux守护程序。我发现了两种方法。 通过调用和设置守护进程。 使用运行程序。 哪个是正确的方法? 问题答案: 来自http://www.steve.org.uk/Reference/Unix/faq_2.html#SEC16 以下是成为守护程序的步骤: 1. fork(),以便父级可以退出,这会将控制权返回给命令行或shell来调用您的程序。需要执行此步骤,以确保新流程不

    • 问题内容: 这里有人在Golang中编写了守护进程吗?你能指导我如何做吗?欢迎有用的链接。 问题答案: 是的,这已经完成。请参阅go-daemon项目。请注意,启动goroutine 后 在守护进程中发生某些问题。有关详细信息,请参见问题227。 目前,我建议您使用操作系统提供的实用程序。

    • 本文向大家介绍linux下的守护进程,包括了linux下的守护进程的使用技巧和注意事项,需要的朋友参考一下 Linux下的常驻进程的作用不可忽略,但这里面的问题也不能忽略,怎么启动进程,怎么结束进程,怎么在进程挂掉之后重启进程都要设计的合理。下面看一个shell控制的php常驻进程的例子。 不废话,直接捞干货,上代码,通过代码来讲解更容易理解: 只里面有几个要强调的地方: 我用这个shell去调用

    • 问题内容: 在Google上搜索会发现x2代码段。第一个结果是该代码配方的内容,其中包含大量文档和说明,并在下面进行了一些有用的讨论。 但是,另一个代码示例虽然没有包含太多文档,但包含用于传递命令(例如启动,停止和重新启动)的示例代码。它还会创建一个PID文件,可以方便地检查守护程序是否已在运行等。 这些示例都说明了如何创建守护程序。还有其他需要考虑的事情吗?一个样本比另一个样本好吗,为什么? 问

    • 问题内容: 创建可在Linux上使用“服务”运行的Java应用程序的最佳方法是什么?我打算使用此处提供的JSW ,但不能在此上使用许可证(许可证是GPL或据我所知要花钱)。我需要apache样式许可。 我正在使用maven进行构建,因此,如果可以使用maven插件创建服务,那就太好了,但是其他建议也都很棒。 我已经看过Apache Commons Daemon ,是否为此有一个Maven插件?文档