《Unix环境高级编程》:单实例守护进程的实现
来源:互联网 发布:diy单片机与红外线 编辑:程序博客网 时间:2024/05/17 01:23
//《APUE》程序13-1:初始化一个守护进程
//《APUE》程序13-2:保证只运行某个守护进程的一个副本
//《APUE》程序14-5:在文件整体加锁
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <sys/resource.h>
#include <sys/syslog.h>
#include <sys/file.h>
#include <sys/stat.h>
//创建锁文件的路径
#define LOCKFILE "/var/run/daemon.pid"
//锁文件的打开模式
#define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
//输出错误信息并退出
void error_quit(const char *str)
{
fprintf(stderr, "%s\n", str);
exit(1);
}
//对文件fd加上记录锁
int lockfile(int fd)
{
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.l_len = 0;
return fcntl(fd, F_SETLK, &fl);
}
//若程序已经运行,则返回1,否则返回0
int already_running(void)
{
int fd;
char buf[16];
//打开放置记录锁的文件
fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE);
if( fd < 0 )
{
syslog(LOG_ERR, "can't open %s: %s", LOCKFILE, strerror(errno));
exit(1);
}
//试图对文件fd加锁,
//如果加锁失败的话
if( lockfile(fd) < 0 )
{
//如果是因为权限不够或资源暂时不可用,则返回1
if( EACCES == errno ||
EAGAIN == errno )
{
close(fd);
return 1;
}
//否则,程序出错,写入一条错误记录后直接退出
syslog(LOG_ERR, "can't lock %s: %s", LOCKFILE, strerror(errno));
exit(1);
}
//先将文件fd清空,然后再向其中写入当前的进程号
ftruncate(fd, 0);
sprintf(buf, "%ld", (long)getpid());
write(fd, buf, strlen(buf)+1);
return 0;
}
//将一个进程变为守护进程
void daemonize(void)
{
int i, fd0, fd1, fd2;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
//见注解1
umask(0);
//获取最大的文件描述号
int temp;
temp = getrlimit(RLIMIT_NOFILE, &rl);
if( temp < 0 )
error_quit("can't get file limit");
//见注解2,
pid = fork();
if( pid < 0 )
error_quit("can't fork");
else if(pid != 0)
exit(0);
//见注解3
setsid();
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
temp = sigaction(SIGHUP, &sa, NULL);
if( temp < 0 )
error_quit("can't ignore SIGHUP");
////确保子进程不会有机会分配到一个控制终端
pid = fork();
if( pid < 0 )
error_quit("can't fork");
else if(pid != 0)
exit(0);
//见注解4
temp = chdir("/");
if( temp < 0 )
error_quit("can't change directoy to /");
//见注解5
if( rl.rlim_max == RLIM_INFINITY )
rl.rlim_max = 1024;
for(i=0; i<rl.rlim_max; i++)
close(i);
//见注解6
fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
if( fd0 != 0 ||
fd1 != 1 ||
fd2 != 2 )
{
syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
fd0, fd1, fd2);
exit(1);
}
}
//该主函数是我原创的,呵呵
int main(void)
{
//打开系统的日志文件
openlog("my test log: ", LOG_CONS, LOG_DAEMON);
daemonize();
//如果程序已经运行,则向记录文件中写入一句话,然后退出
if( already_running() )
{
syslog(LOG_ERR, "daemon alread running");
closelog();
return 1;
}
//向日志文件写入程序的开始(当前)时间,
//过100秒后,再向记录文件写入结束时间,然后结束程序
time_t tt = time(0);
syslog(LOG_INFO, "the log program start at: %s",
asctime(localtime(&tt)) );
sleep(100);
//pause()
tt = time(0);
syslog(LOG_INFO, "the log program end at: %s",
asctime(localtime(&tt)) );
//关闭日志文件
//虽然不关也没事,但为了和openlog配对,还是将它写上去吧
closelog();
return 0;
}
- 《Unix环境高级编程》:单实例守护进程的实现
- 《Unix环境高级编程》:单实例守护进程的实现
- UNIX环境高级编程学习之第十三章守护进程 - 单实例的守护进程
- UNIX环境高级编程——单实例的守护进程
- 《UNIX环境高级编程》笔记--守护进程
- unix环境高级编程-守护进程
- unix环境高级编程--进程关系与守护进程
- UNIX高级编程-守护进程
- UNIX环境高级编程读书笔记(十三)—守护进程
- UNIX环境高级编程读书笔记(十三)—守护进程
- 《UNIX环境高级编程》第13章 守护进程 【读书笔记】
- UNIX环境高级编程——守护进程
- UNIX环境高级编程——守护进程列表
- UNIX环境高级编程——守护进程
- UNIX环境高级编程——初始化一个守护进程
- UNIX环境高级编程(第13章 守护进程)
- UNIX环境高级编程-第13章- 守护进程
- 《unix环境高级编程》-13、守护进程-读书笔记
- js/jquery遍历select下拉框的值
- Guava学习笔记:Guava cache
- VC宏定义 及常用宏定义说明
- 配置Linux+Nginx+PHP+MySQL运行环境
- CA浏览器论坛峰会成功在京举行
- 《Unix环境高级编程》:单实例守护进程的实现
- Guava学习笔记:EventBus
- HDU 2888 Check Corners 二维RMQ
- jboss1.7中配置域名直接访问
- static全局变量,导致数据冲突严重错误
- 单例模式的七种写法
- Guava学习笔记:Range
- linux grep命令学习与总结
- sed学习笔记