提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
一、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 程序名字)