1,守护进程
为什么需要守护进程?
其实守护进程又叫做精灵进程, 她会像精灵一样在背后默默地为你提供帮助。 其实你的计算机之所以能为你干这么多的事,就是因为在计算机的背后有一大群精灵默默地在施展魔法!
Unix/Linux中的守护进程(Daemon)类似于Windows中的后台服务进程,你打开任务管理器看到的那些程序就是守护进程,一直在后台长时间默默运行。
它通常在系统启动后就运行,没有控制终端,也无法和前台的用户交互,在系统关闭时才结束。
UNIX下的网络服务程序,如WebServer(Nginx、Apache等),FTP(vsftp),SSH(openssh)等一般都是由守护进程(Daemon)来实现的。用ps可以查看,守护进程以d结尾,例如sshd。
那我们怎么创造一个精灵为我们施展魔法呢?就离不开demon()函数了。
#include <unistd.h>
int daemon(int nochdir, int noclose);
- 其中参数 nochdir 指定是否要切换当前工作路径到"/"根目录,
- 参数noclose 指定是否要关闭标准输入、标准输出和标准出错 (即重定向到/dev/null)。在创建守护进程的时候,往往需要将进程的工作目录修改为"/"根目录,并将标准输入、标准输出和标准出错关闭。
- 所以这两个参数我们一般都是传0。
- 返回值:成功返回0, 失败返回-1.
2,系统日志syslog
守护进程在后台运行,那我们怎么才能知道它的执行过程呢?
这时候就需要日志了。而系统日志就相当于计算机写的日记一样,它记录着所有进程运行的历史记录,因为系统日志记录的是计算机所有进程运行的状态记录,所以我们自己进程的运行记录很容易被冲刷掉,所以我们用户可以写自己的日志系统。
下面我们介绍一下Linux系统自带的日志系统 syslog 函数:
void openlog(const char *ident, int option, int facility);//打开日志设备,以供读取和写入
- 参数说明:
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_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);//关闭日志设备
3, 示例代码
下面是deamon()和system()的简单例子
$ vim daemon.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <libgen.h>
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_EMERG, "prgrm '%s' start a emerger running", progname); //写入日志的信息
while (1)//此程序要干的事
{
;
}
closelog();//关闭日志
return 0;
}
$gcc daemon.c -o daemon
$./daemon
$cat /var/log/syslog //可以查看日志
所有程序(包括Linux内核) 调用syslog()函数的输出相关信息都会记录到 /var/log/messages 日志文件中,因为该文件中记录 了所有的信息,这也意味着当前程序记录的消息容易被别的程序冲刷掉,所以我们在做项目写网络程序的时候,一般会使用标准 文件IO库(fopen、fwrite()等)自己实现日志系统,而不是直接调用该函数。