zoukankan      html  css  js  c++  java
  • 创建守护进程

    守护进程(daemon)
    守护进程是一个后台进程,它无需用户输入就能运行,经常是提供某种服务。
    Linux做为服务器是,主要的进程也都是为系统或者用户提供后台服务功能。
    常见的守护进程有Web服务器、邮件服务器以及数据库服务器等等。
    守护进程不能够控制终端,所以任何输入或者输出都需要做特殊处理。
     
     
    守护进程看上去似乎很神秘,但如果牢记几条规则而且知道几个关键函数,工作就很简单了。
    首先执行fork后让父进程退出。
    和多数程序一样,一个守护进程是从shell脚本或者命令行启动的。
    但守护进程和应用程序不一样,因为它们不是交互式的
      –它们在后台因而没有控制终端。
    父进程在fork子进程退出后就消除了控制终端。
    守护进程既不需要从标准输入设备读信息,也不需要从标准输出设备输出信息。
     
     
    下一步是在子进程中使用setsid调用创建新会话,调用setsid完成以下几项工作。
      –如果调用进程不是一个进程组的领导进程,它就创建一个新会话,让调用进程成为新会话的会话领导。
      –它让调用进程成为新进程组的进程组领导。
      –它把进程组ID(PGID)和会话ID(SID)设置为调用进程的进程ID(PID)。
      –它取消进程和任何控制终端的关联。
     
    下一步是让根目录成为子进程的当前工作目录。
    因为任何进程如果它的当前目录是在一个被安装的文件系统上,那么就会妨碍这个文件系统被卸载。
     
     
    接下来设置进程的umask为0。
    为了避免守护进程集成的umask收到创建文件和目录操作的干扰,这一步是必要的。
    如果一个进程集成了父进程的umask 055,他屏蔽掉了group和other的读和执行权。如果守护进程接着创建了一个文件,那么对group和other用户操作这个文件会带来麻烦。
    守护进程调用 umask 0避免了这种情况,当创建文件的时候给予守护进程更大的灵活性。
     
     
     
    最后关闭子进程继承的任何不必要的文件描述符
    对于子进程来说,没有理由保持从父进程继承来的打开的文件描述符。
    具体关闭哪些取决与具体的守护进程需要和要求,很难精确的说明规则。
     
     
     
    创建守护进程步骤总结
      –父进程中执行fork后,执行exit退出。
      –在子进程中调用setsid。
      –让根目录“/”成为子进程的工作目录。
      –把子进程的umask变为0。
      –关闭任何不需要的文件描述符。
     
     
    setsid函数
    pid_t setsid()
    setsid函数创建一个新会话和一个新进程组,然后守护进程成为新会话的会话领导,以及新进程组的进程组领导。
    setsid调用还保证新会话没有控制终端。
    如果调用进程已经是一个进程组的领导进程,setsid调用失败。
    setsid调用成功返回新会话ID,失败返回-1,并设置errno。
     
     
    chdir函数
    int chdir(const char *pathname)
    chdir函数根据参数pathname设置当前工作。
    chdir调用成功返回0,失败返回-1,并设置errno。
     
     
    umask函数
    mode_t umask(mode_t mask);
    umask调用把守护进程的umask设置为0,这样取消了来自父进程的umask,它们能够潜在的干扰创建文件和目录。
     
    创建守护进程代码例子。
    void setdaemon()
    {
        pid_t pid, sid;
        pid = fork();
        if (pid < 0)
        {
            printf("fork failed
    ");
            exit(EXIT_FAILURE);
        }
        if(pid > 0)
        {
            exit(EXIT_SUCCESS);//in the parent
        }
        if((sid = setsid()) < 0)
        {
            printf("setsid failed
    ");
            exit(EXIT_FAILURE);
        }
        if((chdir("/")) < 0)
        {
            printf("chdir failed
    ");
            exit(EXIT_FAILURE);
        }
        umask(0);
        //close(STDIN_FILENO);//if close stdin,then daemon_console failed
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
    }
    一旦系统调用setsid,它就不再有控制终端,所以也就无处发送正常情况下应该发往stdout或者stderr的输出。
    可以通过syslog提供服务,记录守护进程的各种输出信息。
     
     
    openlog函数打开日志,syslog写入日志,closelog关闭日志。
    #include <syslog.h>
    void openlog(const char *ident, int option, int facility);
    void syslog(int priority, const char *format, ...);
    void closelog(void);
     
    openlog函数发起到系统日志服务器的连接,参数ident是要向每个消息加入的字符串,典型的情况是要设置成程序的名称。
    参数option是下面一个或多个值的“或”

    名称

    含义

    LOG_CONS

    如果系统日志服务器不能用,写入控制台

    LOG_NDELAY

    立即打开连接,正常情况下,直到发送第一条消息才打开连接

    LOG_PERROR

    打印输出到stderr

    LOG_PID

    每条消息中包含进程 PID

    参数facitity指定程序发送消息的类型。

    名称

    含义

    LOG_AUTHPRIV

    安全授权消息

    LOG_CRON

    时钟守护进程:cron和at

    LOG_DAEMON

    其他系统守护进程

    LOG_KERN

    内核消息

    LOG_LPR

    打印机子系统

    LOG_MAIL

    邮件子系统

    LOG_USER

    默认

    参数priority指定消息的重要性。

    名称

    含义

    LOG_EMERG

    系统不能使用

    LOG_ALERT

    立即采取措施

    LOG_CRIT

    紧急事件

    LOG_ERR

    出错条件

    LOG_WARNING

    警告条件

    LOG_NOTICE

    正常但重大事件

    LOG_INFO

    信息消息

    LOG_DEBUG

    调试信息

    syslog代码例子:

    yslog(LOG_INFO, "my daemin is OK");

    严格的说,openlog和closelog是可选的,因为函数syslog在首次使用的时候自动打开日志文件。
    linux系统上日志文件通常是/var/log/messages。
     
     
     
  • 相关阅读:
    Leetcode 1489找到最小生成树李关键边和伪关键边
    Leetcode 113 路径总和 II
    hdu 1223 还是畅通工程
    hdu 1087 Super Jumping! Jumping! Jumping!
    hdu 1008 Elevator
    hdu 1037 Keep on Truckin'
    湖工oj 1241 畅通工程
    湖工oj 1162 大武汉局域网
    hdu 2057 A + B Again
    poj 2236 Wireless Network
  • 原文地址:https://www.cnblogs.com/shichuan/p/4496188.html
Copyright © 2011-2022 走看看