apue--deamon守护进程、syslog日志、signal信号sigaction信号

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、deamon进程

1.deamon守护进程介绍

类似于Windows中的后台服务进程,一直在后台长时间运行的进程,不会随着terminal的退出而结束。
通常在系统启动后就运行,没有控制终端。也无法和前台的用户交互,在系统关闭时才结束。

网络服务程序的常用模式:
创建套接口,绑定套接口,置套接口为监听模式后,变成守护进程进入后台执行而不占用控制终端。

• Daemon程序一般都作为服务程序使用等待客户端程序与它通信。
• WebServer(Nginx、Apache等),FTP(vsftp),SSH(openssh)等一般都是由守护进程(Daemon)来实现
• 一般都命名为 *d,守护进程一旦脱离了终端,ps 命令查出进程ID然后再使用kill命令停止

Linux基本命令运行符(&) 可以让该命令在后台运行make &只是造成了make在后台一直运行的假象,没有脱离和terminal之间的父子当terminal退出后,make依然会退出。

2.deamon()函数使用

创建daemon进程的库函数

#include <unistd.h>
int daemon(int nochdir, int noclose);
参数 nochdir :指定是否要切换当前工作路径到"/"根目录
参数 noclose :指定是否要关闭标准输入、标准输出和标准出错
(即重定向到/dev/null)两个参数我们一般都是传0

二、syslog日志

1.日志介绍

在后台默默运行的守护进程,一般会关闭三个标准I/O,查看程序的运行状态信息:

	1. 自己写函数把程序运行的而相关信息记录到文件中
	2. 使用Linux系统自带的syslog日志机制,记录设备的日志

UNIX的系统日志是通过syslogd这个进程记录系统有关事件记录,也可以记录应用程序运作事件。
还可以实现运行syslog协议的机器间通信,通过分析这些网络行为日志,藉以追踪掌握与设备和网络有关的状况

2.参数说明


#include <syslog.h> 

void openlog(const char *ident, int option, int facility);
  
函数说明:打开日志设备,以供读取和写入,与文件系统调用的open类似;调用openlog是可选择的。如果不调用openlog,则在第一次调用syslog时,自动调用openlog。

参数说明:              
ident:是一个标记,ident 所表示的字符串将固定的加在每行日志的前面一标识这个日志,通常就写成当前程序的名称
option: 指定openlog函数和接下来调用的syslog函数的控制标志。
可以取以下值:
LOG_CONS:如果将信息发送给 syslogd 守护进程时发生错误,直接将相关信息输出到终端  
LOG_NDELAY:立即打开与系统日志的连接(通常情况下,只有在产生第一条日志信息的情况下才会打开与日志系统的连接)
LOG_ODELAY:类似于 LOG_NDELAY 参数,与系统日志的连接只有在 syslog 函数调用时才会创建 
LOG_PERROR:在将信息写入日志的同时,将信息发送到标准错误输出
LOG_PID:每条日志信息中都包含进程号  

facility:指定记录消息程序的类型,与syslogd守护进程的配置文件 syslog.conf 中的 facility 对应。
可取如下值:
LOG_AUTH                    认证系统(login、su、getty等)  
LOG_AUTHPRIV                同 LOG_AUTH 但只登陆到所选择的单个用户可读的文件中。  
LOG_CRON                    cron 守护进程  
LOG_DAEMON                  其他系统守护进程,如 routed  
LOG_FTP                     文件传输协议:ftpd、tftpd  
LOG_KERN                    内核产生的消息  
LOG_LPR                     系统打印机缓冲池:lpr、lpd  
LOG_MAIL                    电子邮件系统  
LOG_NEWS                    网络新闻系统  
LOG_SYSLOG                  由 syslogd(8)产生的内部消息  
LOG_USER                    随机用户进程产生的消息  
LOG_UUCP                    UUCP 子系统  
LOG_LOCAL0 ~ LOG_LOCAL7     本地使用保留


void syslog(int priority, const char *format, ...);
函数说明:写入日志,与文件系统调用 printf使用方法类似,但在前面指定日志级别。 
参数说明:
priority:表示消息的级别,与 syslogd 守护进程的配置文件 syslog.conf 中的 level 对应。可取如下值:  
LOG_EMERG                   紧急情况  
LOG_ALERT                   应该被立即改正的问题,如系统数据库破坏  
LOG_CRIT                    重要情况,如硬盘错误  
LOG_ERR                     错误  
LOG_WARNING                 警告信息  
LOG_NOTICE                  不是错误情况,但是可能需要处理
LOG_INFO                    情报错误  
LOG_DEBUG                   包含情报的信息,通常指在调试一个程序时使用

void closelog(void);
函数说明:关闭日志设备,与文件系统调用的close类似;
调用closelog也是可选择的,它只是关闭被用于与syslog守护进程通信的描述符。
`

3.编程示例

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <libgen.h> /* basename() */

int main(int argc, char **argv)
{
 char      *progname = basename(argv[0]);

 if( daemon(0, 0) < 0)
  {
        printf("Program daemon() failure: %s\n", strerror(errno));
    return -1;
  }

 openlog("daemon", LOG_CONS | LOG_PID, 0);
 syslog(LOG_NOTICE,  "Program '%s'start running\n",  progname);
 syslog(LOG_WARNING,  "Program '%s' running with a warnning message\n",progname );
 syslog(LOG_EMERG,  "Program '%s' running with a emergency message\n", progname );

 while(1)
  {
   //Do Something here;
  }

 syslog(LOG_NOTICE, "Program '%s' stop running\n",  progname);
 closelog();
 return 0;
}

4.查看日志

 tail -2 /var/log/messages
 tail -2 /var/log/syslog(有一些是在syslog里)

5.查看进程号并关闭进程

 ps aux | grep ./daemon
 kill 18627

三、signal()和sigaction()信号

1.信号的作用

使用 kill 命令杀死程序,让程序“优雅”地退出。

通知进程发生了异步事件,进程之间可以互相通过系统调用kill()发送软中断信号。

	1.  类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数由该函数来处理。
	2. 忽略某个信号,对该信号不做任何处理,就象未发生过一样。
	3. 对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信号的缺省操作是使得进程终止。

不可靠信号:信号值小于SIGRTMIN的信号
可靠信号:信号值大于SIGRTMIN的新增加的一些信号

可以使用 kill -l 命令查看当前系统支持的信号

2.常用信号

在这里插入图片描述

3.Linux下有signal()和sigaction()两种信号安装的函数:

Signal()

	#include <signal.h>
	typedef void (*sighandler_t)(int);
	sighandler_t signal(int signum, sighandler_t handler);

signal函数也会堵塞当前正在处理的signal,但是没有办法阻塞其它signal,比如正在处理SIG_INT,再来一个SIG_INT则会堵塞,但是来SIG_QUIT则会被其中断,如果SIG_QUIT有处理,则需要等待SIG_QUIT处理完了,SIG_INT才会接着刚才处理。

编程示例

  1 #include <signal.h>
  2 #include <stdio.h>
  3 #include <unistd.h>
  4 
  5 void ouch(int sig)
  6 {
  7     printf("I got signal %d\n", sig);
  8     // (void) signal(SIGINT, SIG_DFL);
  9     //(void) signal(SIGINT, ouch);
 10 
 11 }
 12 
 13 
 14 
 15 int main()
 16 {
 17     (void) signal(SIGINT, ouch);
 18 
 19     while(1)
 20     {
 21         printf("hello world...\n");
 22         sleep(1);
 23     }
 24 }

Sigaction()

sigaction函数的功能是检查或修改与指定信号相关联的处理动作

	int sigaction(int signum, const struct sigaction *act,
					struct sigaction *oldact);
					
signum参数:指出要捕获的信号类型
act参数:指定新的信号处理方式
oldact参数:输出先前信号的处理方式(如果不为NULL的话)

struct sigaction结构体介绍
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
1. 阻塞

sigaction函数有阻塞的功能,比如SIGINT信号来了,进入信号处理函数,默认情况下,在信号处理函数未完成之前,如果又来了一个SIGINT信号,其将被阻塞,只有信号处理函数处理完毕,才会对后来的SIGINT再进行处理,同时后续无论来多少个SIGINT,仅处理一个SIGINT,sigaction会对后续SIGINT进行排队合并处理。

2. sa_mask,信号屏蔽集

可以通过函数sigemptyset/sigaddset等来清空和增加需要屏蔽的信号,上面代码中,对信号SIGINT处理时,如果来信号SIGQUIT,其将被屏蔽,但是如果在处理SIGQUIT,来了SIGINT,则首先处理SIGINT,然后接着处理SIGQUIT。

3. sa_flags如果取值为0,则表示默认行为。

还可以取如下俩值,但是我没觉得这俩值有啥用。

SA_NODEFER,如果设置来该标志,则不进行当前处理信号到阻塞
SA_RESETHAND,如果设置来该标志,则处理完当前信号后,将信号处理函数设置为SIG_DFL行为

编程示例

 #include <signal.h>
 #include <stdio.h>
 #include <unistd.h>
    
   void ouch(int sig)
   {
       printf("oh, got a signal %d\n", sig);
   
      int i = 0;
      for (i = 0; i < 5; i++)
      {
          printf("signal func %d\n", i);
          sleep(1);
      }
   }
  
  int main()
  {
     struct sigaction act;
     act.sa_handler = ouch;
     sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, SIGQUIT);//如果来信号SIGQUIT,其将被屏蔽,但是如果在处理SIGQUIT,来了SIGINT,则首先处理SIGINT,然后接着处理SIGQUIT。
      // act.sa_flags = SA_RESETHAND;
     // act.sa_flags = SA_NODEFER;
     act.sa_flags = 0;
 
     sigaction(SIGINT, &act, 0);
  
 
    struct sigaction act_2;
     act_2.sa_handler = ouch;
     sigemptyset(&act_2.sa_mask);
     act.sa_flags = 0;
     sigaction(SIGQUIT, &act_2, 0);
 
        while(1)
        {
             sleep(1);
        }
     return ;
 
    }

另开一个终端使用killall命令尝试终止该程序的执行

 killall signal
(killall 程序名字)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值