PS:要转载请注明出处,本人版权所有。
PS: 这个只是基于《我自己》的理解,
如果和你的原则及想法相冲突,请谅解,勿喷。
前置说明
本文作为本人csdn blog的主站的备份。(BlogID=044)
本文发布于 2017-11-17 16:33:04,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=044)
环境说明
无
前言
无
Linux Daemo 和 单例模式
Linux 单例模式
原理:创建一个保存进程名的文件,利用linux的文件锁来判断文件是否加锁来判断是否已有相同的程序运行。
例子
int CheckIsSingleton(int *fd)
{
struct flock loglock;
char nowpid[10];
int num;
if (0 > (*fd = open(LOCK_FILE_NAME, O_WRONLY | O_CREAT, 0600)))
{
perror("open lock file failed!");
return -1;
}
/*
struct flock {
...
short l_type; // Type of lock: F_RDLCK,
//F_WRLCK, F_UNLCK
short l_whence; // How to interpret l_start:
//SEEK_SET, SEEK_CUR, SEEK_END
off_t l_start; // Starting offset for lock
off_t l_len; // Number of bytes to lock
pid_t l_pid; // PID of process blocking our lock
// (set by F_GETLK and F_OFD_GETLK)
...
};
As well as being removed by an explicit F_UNLCK, record locks are auto‐
matically released when the process terminates.
*/
memset(&loglock, 0, sizeof(struct flock));
loglock.l_type = F_WRLCK;
loglock.l_whence = SEEK_SET;
if ( 0 > fcntl(*fd, F_GETLK, &loglock) ){//检查是否能够加F_WRLCK锁,不能够确认文件是否有锁。
close(*fd);
perror("fcntl F_WRLCK failed");
_exit(-1);
}
else{
if ( loglock.l_type != F_UNLCK){
close(*fd);
write(2,"check F_WRLCK failed\n",sizeof("check F_WRLCK failed\n"));//stdout was closed!!!
write(2,"The same process is running\n",sizeof("The same process is running\n"));
_exit(-1);
}
}
loglock.l_type = F_WRLCK;
loglock.l_start = 0; //从文件开始加锁
loglock.l_whence = SEEK_SET;
loglock.l_len = 0; //加锁整个文件
if ( 0 > fcntl(*fd, F_SETLK, &loglock) ){
close(*fd);
perror("fcntl F_WRLCK failed");
printf("The same process is running\n");
_exit(-1);
}
num = sprintf(nowpid, "%d",getpid());
write(*fd, nowpid, num);
return 0;
}
Daemon 简单设计
原理
- 利用fork来实现。setsid使当前子进程成为新的进程组长,在使用fork使其与终端脱离,设置工作目录,设置文件掩码
- 利用系统提供的daemon()(此调用来至于glibc)来完成功能。(底层使用fork来实现)
例子
void CreateDaemonProcess_daemon()//根据daemon函数的源码来看,后面补充了一个fork比较安全
{
/*
The daemon() function is for programs wishing to detach themselves from
the controlling terminal and run in the background as system daemons.
If nochdir is zero, daemon() changes the process's current working
directory to the root directory ("/"); otherwise, the current working
directory is left unchanged.
If noclose is zero, daemon() redirects standard input, standard output
and standard error to /dev/null; otherwise, no changes are made to
these file descriptors.
int
daemon(nochdir, noclose)
int nochdir, noclose;
{
int fd;
switch (__fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}
if (__setsid() == -1)
return (-1);
if (!nochdir)
(void)__chdir("/");
if (!noclose) {
struct stat64 st;
if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1
&& (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0)
== 0)) {
if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0
#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
&& (st.st_rdev
== makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR))
#endif
) {
(void)__dup2(fd, STDIN_FILENO);
(void)__dup2(fd, STDOUT_FILENO);
(void)__dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)__close (fd);
} else {
// We must set an errno value since no
// function call actually failed.
close_not_cancel_no_status (fd);
__set_errno (ENODEV);
return -1;
}
} else {
close_not_cancel_no_status (fd);
return -1;
}
}
return (0);
}
*/
if (0 > daemon(0, 0))
{
perror("daemon call failed!");
_exit(-1);
}
//setsid();
// int fd;
// if ( 0 > (fd = open("/dev/tty", O_RDWR )) ){
// perror("open tty failed!");
// _exit(-1);
// }
// if ( ioctl(fd, TIOCNOTTY, NULL) < 0){
// perror("ioctl TIOCNOTTY failed!");
// close(fd);
// _exit(-1);
// }
// close(fd);
int pid;
pid = fork();
if (pid == -1)
{
perror("fork first error!");
}
else if (pid > 0)
{ //parent 1
_exit(1);
}
else
{ //child pid==0
}
return;
}
void CreateDaemonProcess_Fork()
{
pid_t pid, pid1, pid2;
pid = fork();
if (pid == -1)
{
perror("fork first error!");
}
else if (pid > 0)
{ //parent 1
_exit(1);
}
else
{ //child pid==0
if (0 > (pid1 = setsid()))
{
perror("setsid() call failed!");
_exit(-1); //
}
else
{
printf("New session id is %d\n", pid1);
}
pid2 = fork();
if (pid2 == -1)
{
perror("fork second error!");
}
else if (pid2 > 0)
{ //parent
_exit(1);
}
else
{
chdir("/"); //change current working directory
umask(0);
return;
}
}
}
说明:
- 双fork的原因是进程组长会开启终端。而我们的daemon程序是不需要终端的。
- 文件掩码用于设置默认的文件权限。
- 子进程会继承父进程的大部分属性,包括已打开文件描述符、文件掩码、工作目录等待,这些根据需求处理。
后记
无
参考文献
- 无
![qrc_img](https://flyinskyin2013.github.io/ImageBed0/blogs/qrcode_for_wx_official_account.jpg)
PS: 请尊重原创,不喜勿喷。
PS: 要转载请注明出处,本人版权所有。
PS: 有问题请留言,看到后我会第一时间回复。