您的位置:首页 > 运维架构 > Linux

Linux 守护进程Daemon

2017-03-11 21:39 267 查看

前言

守护进程是生存期长的一种进程。

Linux常用于服务器,程序通常不运行在前台。运行于前台的进程和终端关联,一旦终端关闭,进程也随之退出。因为守护进程不和终端关联,因此它的标准输出和标准输入也无法工作,调试信息应该写入到普通文件中,以便将来进行错误定位和调试。而且守护进程通常以root权限运行。

编写规则

调用umask将文件模式创建屏蔽只设置为一个已知值

调用fork,让父进程退出

调用setuid创建新会话

将当前工作目录更改为根目录

关闭不再需要的文件描述符

重定向标准输入/标准输出/标准错误到/dev/null

和终端脱离关系

程序示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <syslog.h>
int main()
{
pid_t pid = fork();
if(pid == 0)
{
pid = fork();
if(pid == 0)
{
// daemon process
umask(0);  // 设置掩码
setsid(); // 让自己变成session leader
chdir("/");  // 修改当前目录
chroot("/");

// 获取最大的已经打开的文件描述符
int maxfd = 1024; // 演示
// 把所有文件关闭
int i;
for(i=0; i<=maxfd; ++i)
{
close(i);
}

// 重定向0、1、2文件到/dev/null
open("/dev/null", O_RDONLY); // 标准输入
open("/dev/null", O_WRONLY);  // 标准输出
open("/dev/null", O_WRONLY);  // 标准错误

syslog(LOG_ERR|LOG_KERN, " this is syslog\n");

// 后台进程不退出
while(1)
sleep(1);
}
}
}


出错记录

由于不能再使用标准输入和输出,因此需要调用以下函数来输出调试信息。

#include <syslog.h>
void openlog(const char* ident, int option, int facility);
void syslog(int priority, const char* format, ...);
void closelog(void);
int setlogmask(int maskpri);


单例守护进程

守护程序往往只有一个实例,而不允许多个,可以用文件锁来实现单例。

程序示例:(摘自UNIX环境高级编程)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>

#define LOCKFILE "/var/run/mydaemon.pid"
#define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

extern int lockfile(int);

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));
}

int already_running(const char *filename)
{
int fd;
char buf[16];

fd = open(filename, O_RDWR | O_CREAT, LOCKMODE);
if (fd < 0) {
syslog(LOG_ERR, "can't open %s: %m\n", filename);
exit(1);
}
if (lockfile(fd) == -1) {
if (errno == EACCES || errno == EAGAIN) {
syslog(LOG_ERR, "file: %s already locked", filename);
close(fd);
return 1;
}
syslog(LOG_ERR, "can't lock %s: %m\n", filename);
exit(1);
}
ftruncate(fd, 0);
sprintf(buf, "%ld", (long)getpid());
write(fd, buf, strlen(buf) + 1);
return 0;
}

int main(int argc, char *argv[])
{
if (already_running(LOCKFILE))
return 0;

printf("start main...\n");
sleep(100);
printf("main done!\n");

exit(0);
}


惯例

单例文件路径在/var/run目录下,内容为该进程ID

配置文件应该在/etc目录下

守护的启动脚本通常放在/etc/init.d目录下

守护进程将捕捉SIGHUP信号重新读取配置文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 服务器