一、守护进程的特征
① 查看系统常见的系统守护进程
其中系统守护进程:
kswapd:内存换页守护进程。支持虚拟内存子系统在一段时间后把脏页面慢慢的回写磁盘来回收这些页面的内存资源。
flush:在可用内存达到设置的最小阈值时讲脏页面写入写入磁盘
sysnc_supers:定期将西戎的元数据冲洗至磁盘。
jdb: 帮助实现ext4文件系统的中日志功能。
关于脏页面的理解
二、守护进程的特点
① 所有守护进程都没有控制终端,其终端名字被设置成问号(即tty那一列显示 ? )
② 用户层守护进程缺少控制终端可能是守护进程调用了setsid造成的。setid当守护进程脱离当前登录会话,由于会话和控制终端具有独占性所以控制终端也也脱离了。
③ 因为调用了setid,大多数用户层守护进程都是进程组组长以及会话的首进程。
④ 注意用户层守护进程的父进程是init进程。
三、守护进程的启动方法
① 在系统启动的阶段,大多数系统的守护进程都是由系统初始化脚本启动的。这些脚本文件一般在/etc 或者 /etc/rc开头的的某个目录中,一般都是用超级用户权限运行的。
② 某些常见的网络服务器也是通过这些脚本启动守护进程的inetd、wed服务器
③ 内核守护进程以无控制中终端的模式启动。
四、创建守护进程的思路
① 调用umask将文件模式创建的掩码设置为0。
② 调用fork函数然父进程exit,
使得子进程是一个孤儿进程,相当于是由一个简单的shell目录创建出来的
使得子进程不是进程组长。
③ 调用setsid函数创建一个会话,
使子进程成为新会话的首进程
使子进程成为进程组组长
使子进程没有控制终端
④ 将当前工作目录更改为根目录
⑤ 关闭不在需要的文件描述符
守护进程并不与终端设备相关联,所以其输出无处显示,
也无发通过交互式获取用户哪里接受输入
五、 初始化一个守护进程
#include <stdio.h>
#include <syslog.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/resource.h>
void Daemonize(const char * cmd);
void Daemonize(const char * cmd)
{
struct rlimit rl;//获取关于文件描述符的信息结构体
//设置掩码为000
umask(0000);
//获取文件描述符的最大数量
if(getrlimit(RLIMIT_NOFILE,&rl) < 0)
{
perror("getrlimeit failed");
return ;
}
printf("---%ld\n",rl.rlim_max);
//创建子进程
pid_t pid = fork();
if(pid == -1)
{
perror("fork failed ... ");
return ;
}
else if(pid != 0)
{
exit(0);//父进程退出
}
setsid();//创建会话终端 设置子进程为新的进程组组长
//设置工作路径为根目录
if(chdir("/") < 0)
{
perror("chidr failed");
return ;
}
if(rl.rlim_max == RLIM_INFINITY)
{
rl.rlim_max = 1024;
}
for(int i=0; i<rl.rlim_max; i++)
{
close(i);
}
//打开空设备文件null,对他进行重定向输入和输出
int fd_null = open("/dev/null",O_RDWR);
int fd_stdin = dup(0);
int fd_stdout = dup(0);
//启动程序的日志记录处理功能
openlog(cmd,LOG_CONS,LOG_DAEMON);
//cmd命令:自定义记录日志前缀文
//LOG_CONS:当输出报告不能通过 UNIX 本地网络(内环网) 传输时(AF_UNIX, AF_LOCAL Local communication ),在终端输出该报告
//LOG_DAEMON:消息类型为系统守护进程类型
//判断三个标准是否重定向成功,不成功则靠syslog显示出错信息
if(fd_null != 0 || fd_stdin != 1 || fd_stdout != 2)
{
syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd_null,fd_stdin,fd_stdout);
exit(-1);
}
return ;
}
int main()
{
Daemonize("cyz_user_cmd:");
while(1)
{
sleep(1);
}
return 0;
}
运行结果:
cyz@ubuntu:/mnt/hgfs/code$ ps -efj
cyz 9011 2102 9011 9011 96 08:59 ? 00:00:16 ./daemonize
cyz@ubuntu:/mnt/hgfs/code$ ps -efj | grep 9011
cyz 9011 2102 9011 9011 99 08:59 ? 00:00:57 ./daemonize
cyz 9021 2740 9020 2740 0 09:00 pts/19 00:00:00 grep --color=auto 9011