• 创建守护进程


    守护进程(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。
     
     
     
  • 相关阅读:
    WPF Prefix 'attach' does not map to a namespace.
    C# 用ManulResetEvent 控制Thread的 Suspend、Resume
    C# 监控Windows睡眠与恢复
    c# DataTable to Object Mapping
    C# DispatcherTimer Start之后立即执行
    Visual studio 编译时copy文件、文件夹
    c# 无法加载xxx.dll 找不到指定的模块(如何指定文件夹)
    EntityFramework 找不到方法:“Void System.Data.Entity.DbModelBuilder.RegisterEntityType
    wpf 全局异常捕获处理
    pandas入门
  • 原文地址:https://www.cnblogs.com/shichuan/p/4496188.html
Copyright © 2020-2023  润新知