APUE笔记-守护进程

守护进程

编程步骤:

1、umask将屏蔽字改为已知值(通常为0)

2、调用fork然后师父进程exit。(子进程继承父进程的组ID,子进程获得新的ID,并且不是组长。)

3、setsid创建新的会话。(做了三件事:成为新会话首进程、成为新进程组的组长、没有控制终端。)

忽略掉SIGHUP信号,这个信号和控制终端有关。

再次fork并且使父进程exit,使守护进程不是会话首进程,防止取得控制终端。因为SVR4中:如果进程是会话首进程,并且没有控制终端,当该首进程打开终端设备时,如果这个终端不是其他会话的控制终端,这个终端就会自动成为该会话的控制终端。所以第二次fork使得守护进程不是会话首进程,就无法取得控制终端。

4、将当前工作目录改为根目录(从父进程继承的工作目录可能在一个挂载文件系统中。)

5、关闭不需要的文件描述符。

6、打开/dev/null使其具有0,1,2文件描述符。

实验:创建守护进程

    1 #include <stdio.h>                                                                                                                              
    2 #include "apue.h"
    3 #include <sys/resource.h>
    4 #include <signal.h>
    5 #include <syslog.h>
    6 int main()
    7 {
    8     pid_t pid;
    9     pid_t fd0,fd1,fd2;
   10     struct sigaction sa;
   11     struct rlimit rl;
   12     if(getrlimit(RLIMIT_NOFILE,&rl)<0)
   13     {
   14         perror("getrlimt");
   15         exit(1);
   16     }
   17     umask(0);
   18     pid  = fork();
   19     if(pid<0)
   20     {
   21         perror("fork");
   22         exit(2);
   23     }
   24     else if(pid>0)
   25     {
   26         exit(3);
   27     }
   28     setsid();
   29     sa.sa_flags=0;
   30     sa.sa_handler=SIG_IGN;
   31     sigemptyset(&sa.sa_mask);
   32     if(sigaction(SIGHUP,&sa,NULL)<0)
   33     {
   34         perror("sigaction");
   35         exit(4);
   36     }
   37     if((pid=fork())<0)
   38     {
   39         perror("fork");
   40         exit(5);
   41     }
   42     else if(pid>0)
   43     {
   44         exit(0);
   45     }
   46     if(chdir("/")<0)
   47     {
   48         perror("chdir");
   49         exit(6);
   50     }   
   51     if(rl.rlim_max==RLIM_INFINITY)//限制值可能是一个“无穷大”值:RLIM_INFINITY。
   52         rl.rlim_max=1024;
   53     for(int i=0;i<rl.rlim_max;i++)
   54     {
   55         close(i);
   56     }
   57     fd0 = open("/dev/null",O_RDWR);
   58     fd1 = dup(fd0);
   59     fd2 = dup(fd0);
   60     while(1);
   61 }                  

出错记录

1、没有终端,因此错误没法输出。

2、每个守护进程输出到一个文件,比较乱,不好管理。

3、syslog设施。

#include <syslog.h> 
void openlog(const char *ident, int option, int facility);
void syslog(int priority, const char *format, ...);
void closelog(void); 
int setlogmask(int mask);

介绍如何使自己的程序输出信息到日志文件

环境ubantu

1、找到syslog.h函数的头文件

/usr/include/x86_64-linux-gnu/sys里面有syslog.h头文件
下面是这个头文件的一部分内容:一会儿要用到

CODE prioritynames[] =
 75   {
 76     { "alert", LOG_ALERT },
 77     { "crit", LOG_CRIT },
 78     { "debug", LOG_DEBUG },
 79     { "emerg", LOG_EMERG },
 80     { "err", LOG_ERR },
 81     { "error", LOG_ERR },       /* DEPRECATED */
 82     { "info", LOG_INFO },
 83     { "none", INTERNAL_NOPRI },     /* INTERNAL */
 84     { "notice", LOG_NOTICE },
 85     { "panic", LOG_EMERG },     /* DEPRECATED */
 86     { "warn", LOG_WARNING },        /* DEPRECATED */
 87     { "warning", LOG_WARNING },
 88     { NULL, -1 }
 89   };



#ifdef SYSLOG_NAMES
122 CODE facilitynames[] =
123   {
124     { "auth", LOG_AUTH },
125     { "authpriv", LOG_AUTHPRIV },
126     { "cron", LOG_CRON },
127     { "daemon", LOG_DAEMON },
128     { "ftp", LOG_FTP },
129     { "kern", LOG_KERN },
130     { "lpr", LOG_LPR },
131     { "mail", LOG_MAIL },
132     { "mark", INTERNAL_MARK },      /* INTERNAL */
133     { "news", LOG_NEWS },
134     { "security", LOG_AUTH },       /* DEPRECATED */
135     { "syslog", LOG_SYSLOG },
136     { "user", LOG_USER },
137     { "uucp", LOG_UUCP },
138     { "local0", LOG_LOCAL0 },
139     { "local1", LOG_LOCAL1 },
140     { "local2", LOG_LOCAL2 },
141     { "local3", LOG_LOCAL3 },
142     { "local4", LOG_LOCAL4 },
143     { "local5", LOG_LOCAL5 },
144     { "local6", LOG_LOCAL6 },
145     { "local7", LOG_LOCAL7 },
146     { NULL, -1 }
147   };
148 #endif



2、/var/log里面是各种日志文件和目录,日志都在这里面找

3、修改配置文件:

找到/etc/rsyslog.conf

看到有一行信息:$IncludeConfig /etc/rsyslog.d/*.conf     (说明了配置文件的位置)

进入/etc/rsyslog.d/

里面两个文件:20-ufw.conf  50-default.conf

配置信息存在于50-default.conf中

在这个配置文件添加下面一行:

  user.debug          /var/log/mylog.log(格式:facility.level    action)

重启rsyslogd    /etc/init.d/rsyslog restart

解释:

facility.level    action//之间是TAB键分隔(action可以制定一个文件,systlog输出的信息就在这个文件中)

void syslog(int priority, const char *format, ...);//priority是facility.level 的组合

4、编写代码测试

 1 #include <stdio.h>                                                                                                                                
  2 #include <syslog.h>
  3 int main()
  4 {
  5     openlog("test",LOG_CONS | LOG_PID,0);
  6     syslog(LOG_USER | LOG_DEBUG,"%s\n","hello");
  7     closelog();
  8     return 0;
  9 }
 10 

运行:

可以看到在 /var/log/mylog.log中出现下面信息

Sep 13 21:58:19 myname-HP-Pavilion-14-Notebook-PC test[23764]: helllllllooooo   

 

单实例守护进程:

建立一个文件,加一把写锁。

测试守护进程是否在运行,尝试给锁文件加锁就能测试。

守护进程的惯例:

配置文件被修改了,重启守护进程比较麻烦

因此可以让守护进程接收SIGHUP信号(守护进程没有控制终端,一般不会收到这个信号),重新读取配置文件。

sigwait() :提供了一种等待信号的到来,以串行的方式从信号队列中取出信号进行处理的机制。

sigwait()只等待函数参数中指定的信号集,即如果新产生的信号不在指定的信号集内,则 sigwait()继续等待。

int pthread_sigmask (int how,const sigset_t *set,sigset_t *oset)用作在主调线程里控制信号掩码。

 

执行时关闭:

服务器fork   exec提供服务。

exec后,原来的文件描述符不关闭(在不设置close_on_exec位的情况下),设置执行时关闭,可以防止被执行程序的恶意行为。

如果对文件描述符设置了FD_CLOEXEC,exec后,文件描述符被关闭,fork出来的子进程中,该文件描述符不关闭,仍可使用。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值