一 何为守护进程
- 长期运行。守护进程是一种生存期很长的一种进程,它们一般在系统启动时开始运行,除非强行终 止,否则直到系统关机都会保持运行。与守护进程相比,普通进程都是在用户登录或运行程序时创 建,在运行结束或用户注销时终止,但守护进程不受用户登录注销的影响,它们将会一直运行着、 直到系统关机。
- 与控制终端脱离。在 Linux 中,系统与用户交互的界面称为终端,每一个从终端开始运行的进程都 会依附于这个终端,这是上一小节给大家介绍的控制终端,也就是会话的控制终端。当控制终端被 关闭的时候,该会话就会退出,由控制终端运行的所有进程都会被终止,这使得普通进程都是和运 行该进程的终端相绑定的;但守护进程能突破这种限制,它脱离终端并且在后台运行,脱离终端的 目的是为了避免进程在运行的过程中的信息在终端显示并且进程也不会被任何终端所产生的信息 所打断。 守护进程是一种很有用的进程。Linux 中大多数服务器就是用守护进程实现的,譬如,Internet 服务器 inetd、Web 服务器 httpd 等。同时,守护进程完成许多系统任务,譬如作业规划进程 crond 等。 守护进程 Daemon,通常简称为 d,一般进程名后面带有 d 就表示它是一个守护进程。守护进程与终端 无任何关联,用户的登录与注销与守护进程无关、不受其影响,守护进程自成进程组、自成会话,即 pid=gid=sid。通过命令"ps -ajx"查看系统所有的进程,如下所示
二 编写守护进程程序
umask(user file-creatiopn mode mask)是linux中的一个命令,用于为用户文件创建权限掩码,语法“umask [-S][权限掩码]”;其中,“权限掩码”是由3个八进制的数字所组成,将现有的存取权限减掉权限掩码后,即可产生建立文件时预设的权限。
/umask命令可确定要在创建的任何文件或者目录上设置的默认权限。umask命令为用户文件创建掩码,,是创建文件或文件夹时默认权限的基础。通常我们可以使用chmod修改linux中文件的权限.umask的作用与chmod的效果相反,具体看下面。
若没有文件掩码时,文件的默认权限为0666,文件夹的默认权限为0777。
三 示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
// 文件权限掩码 umask 用于对新建文件的权限位进行屏蔽,在 5.5.5 小节中有介绍。由于使用 fork 函数新
// 建的子进程继承了父进程的文件权限掩码,这就给子进程使用文件带来了诸多的麻烦。因此,把文件权限掩
// 码设置为 0,确保子进程有最大操作权限、这样可以大大增强该守护进程的灵活性。设置文件权限掩码的函
// 数是 umask,通常的使用方法为 umask(0)
// umask(user file-creatiopn mode mask)是linux中的一个命令,用于为用户文件创建权限掩码,语法“umask [-S][权限掩码]”;其中,“权限掩码”是由3个八进制的数字所组成,将现有的存取权限减掉权限掩码后,即可产生建立文件时预设的权限。
// umask命令可确定要在创建的任何文件或者目录上设置的默认权限。umask命令为用户文件创建掩码,,是创建文件或文件夹时默认权限的基础。通常我们可以使用chmod修改linux中文件的权限.umask的作用与chmod的效果相反,具体看下面。
// 若没有文件掩码时,文件的默认权限为0666,文件夹的默认权限为0777。
int main(void)
{
pid_t pid;
int i;
/* 创建子进程 */
pid = fork();
if (0 > pid)
{
perror("fork error");
exit(-1);
}
else if (0 < pid) // 父进程
exit(0); // 直接退出
/*
*子进程
*/
/* 1.创建新的会话、脱离控制终端 */
if (0 > setsid())
{
perror("setsid error");
exit(-1);
}
/* 2.设置当前工作目录为根目录 */
if (0 > chdir("/"))
{
perror("chdir error");
exit(-1);
}
/* 3.重设文件权限掩码 umask */
umask(0);
/* 4.关闭所有文件描述符 */
for (i = 0; i < sysconf(_SC_OPEN_MAX); i++)
close(i);
/* 5.将文件描述符号为 0、1、2 定位到/dev/null */
open("/dev/null", O_RDWR);
// 回到dup函数,这个函数有一个参数就是文件描述符, 这个函数创建出一个新的文件描述符,这个文件描述符与参数中的这个文件描述符指向同一个文件, 而且新的文件描述符总是取系统中最小的的整数值
dup(0);
dup(0);
/* 6.忽略 SIGCHLD 信号 */
signal(SIGCHLD, SIG_IGN);
/* 正式进入到守护进程 */
for (;;)
{
sleep(1);
puts("守护进程运行中......");
}
exit(0);
}
gcc -o daemon_process daemon_process.c
运行之后,没有任何打印信息输出,原因在于守护进程已经脱离了控制终端,它的打印信息并不会输出
显示到终端,在代码中已经将标准输入、输出以及错误重定位到了/dev/null,/dev/null 是一个黑洞文件,自然是看不到输出信息。
使用"ps -ajx"命令查看进程,如下所示:
3.1 文件重定向 dup2
上述文件重定向部分 也可用dup2实现
// 5、重定向0,1,2
if ((fd == open("/dev/null", O_RDWR) != -1)) // fd == 3
{
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
// 6、关闭掉不需要的fd
if (fd > STDERR_FILENO)
close(fd);
}
dup2(3, 2); 让2号文件描述符重定向到 log.txt,其实就是把原本3号描述符保存的地址拷贝到2号描述符的位置。、
例子:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int main(){
int fd = open("log.txt", O_CREAT | O_RDWR, 0644);
if(fd < 0)
{
perror("open");
}
dup2(fd, 1); // 文件重定向
printf("newfd: hello, world\n"); // 向1号文件描述符写入内容
const char* buf = "oldfd: hello, world\n";
write(fd, buf, strlen(buf)); // 向原本的log.txt对应的文件描述符写入内容
return 0;
}
3.2 如何输出守护进程log到固定文件
解决办法如下:我们在log.hpp打印日志文件那,用宏定义一个serverTcp.log文件。
利用open函数打开此文件,返回到logFd 利用dup2把标准输入,标准输出重定向到logFd文件
注意 输出实时性。
s y n c只是将所有修改过的块的缓存排入写队列,然后就返回,它并不等待实际I / O操作结束。 系统精灵进程(通常称为u p d a t e )一般每隔3 0秒调用一次s y n c函数。这就保证了定期刷新内 核的块缓存。命令s y n c ( 1 )也调用s y n c函数。
函数f s y n c只引用单个文件(由文件描述符f i l e d e s指定),它等待I / O结束,然后返回。f s y n c可/用于数据库这样的应用程序,它确保修改过的块立即写到磁盘上。比较一下f s y n c和O _ S Y N C标 志(见3 . 1 3节)。当调用f s y n c时,它更新文件的内容,而对于O _ S Y N C,则每次对文件调用w r i t e函数时就更新文件的内容。
fflush和fsync的联系和区别
[zz ] http://blog.chinaunix.net/u2/73874/showart_1421917.html1.提供者fflush是libc.a中提供的方法,fsync是系统提供的系统调用。2.原形fflush接受一个参数FILE *.fflush(FILE *);fsync接受的时一个Int型的文件描述符。fsync(int fd);3.功能fflush:是把C库中的缓冲调用write函数写到磁盘[其实是写到内核的缓冲区]。fsync:是把内核缓冲刷到磁盘上。
c库缓冲-----fflush---------〉内核缓冲--------fsync-----〉磁盘