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 简单设计

  原理

  1. 利用fork来实现。setsid使当前子进程成为新的进程组长,在使用fork使其与终端脱离,设置工作目录,设置文件掩码
  2. 利用系统提供的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;
}
}
}

  说明:

  1. 双fork的原因是进程组长会开启终端。而我们的daemon程序是不需要终端的。
  2. 文件掩码用于设置默认的文件权限。
  3. 子进程会继承父进程的大部分属性,包括已打开文件描述符、文件掩码、工作目录等待,这些根据需求处理。

后记


  无

参考文献


打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

Linux Daemon & 单例模式 设计与实现的更多相关文章

  1. 设计模式之PHP项目应用——单例模式设计Memcache和Redis操作类

    1 单例模式简单介绍 单例模式是一种经常使用的软件设计模式. 在它的核心结构中仅仅包括一个被称为单例类的特殊类. 通过单例模式能够保证系统中一个类仅仅有一个实例并且该实例易于外界訪问.从而方便对实例个 ...

  2. 利用单例模式设计数据库连接Model类

    之前在<[php]利用php的构造函数与析构函数编写Mysql数据库查询类>(点击打开链接)写过的Mysql数据库查询类还不够完美,利用<[Java]单例模式>(点击打开链接) ...

  3. python学习(28) 浅谈可变对象的单例模式设计

    python开发,有时候需要设计单例模式保证操作的唯一性和安全性.理论上python语言底层实现和C/C++不同,python采取的是引用模式,当一个对象是可变对象,对其修改不会更改引用的指向,当一个 ...

  4. [转] Linux Daemon Writing HOWTO

    Linux Daemon Writing HOWTO Devin Watson v1.0, May 2004 This document shows how to write a daemon in ...

  5. [转载] Linux Futex的设计与实现

    Linux Futex的设计与实现 引子 在编译2.6内核的时候,你会在编译选项中看到[*] Enable futex support这一项,上网查,有的资料会告诉你"不选这个内核不一定能正 ...

  6. 创建 SysV 风格的 linux daemon 程序

    本文介绍如何使用 C 语言创建 Linux 系统中 SysV 风格的 daemon 程序.注意:这是一种旧式的 daemon 程序写法,进入 systemd 时代后是不需要通过这样的方式创建 daem ...

  7. .NET跨平台实践:.NetCore、.Net5/6 Linux守护进程设计

    之前,我写过两篇关于用C#开发Linux守护进程的技术文章,分别是<.NET跨平台实践:用C#开发Linux守护进程>和<.NET跨平台实践:再谈用C#开发Linux守护进程 - 完 ...

  8. Linux UBI子系统设计初探

    问题领域 flash存储设备存在如下特点: 存在坏块 使用寿命较短 存储介质不稳定 读写速度慢 不支持随机访问(nand) 只能通过擦除将0改成1 最小读写单位为page or sub-page 便宜 ...

  9. Linux Daemon 类程序

    1.后台daemon程序(精灵程序) 在Linux中专门提供了一个函数来完成这个daemon化的过程,这个函数的原型如下 int daemon (int __nochdir, int __noclos ...

  10. python to be linux daemon

    所需第三方库:python-daemon[https://pypi.python.org/pypi/python-daemon/] 使用方式: python linux_service.py star ...

随机推荐

  1. jackson、objectMapper 、JsonAlias、JsonProperty、json。序列化和反序列化研究。

    总结: @JsonAlias:序列化出来是一定是真名,反序列化时可以传真名(驼峰)Json也可以传别名(下划线)Json @JsonProperty:序列化出来一定是别名,反序列化时也只能传别名Jso ...

  2. CF1859

    A 让 \(c\) 保存数组中所有最大的数,如果所有数都相等则 \(-1\). B 只需要记录每个序列的最小值和次小值,然后对次小值求前后缀和. C 枚举最大值 \(mx\),然后遍历 \(i:n\s ...

  3. react 聊聊setState异步背后的原理,react如何感知setState下的同步与异步?

    壹 ❀ 引 在react中的setState是同步还是异步?react为什么要将其设计成异步?一文中,我们介绍了setState同步异步问题,解释了何种情况下同步与异步,异步带来了什么好处,以及rea ...

  4. Centos7和Centos8的NFS配置

    Centos7和Centos8的NFS配置几乎是完全一样的 服务端 Centos7默认安装了rpcbind, nfs-utils, 其中rpcbind的服务默认是启用的, nfs-utils默认是禁用 ...

  5. QT C++工程CI环境笔记

    开发环境 Ubuntu18.04 or Ubuntu20.04 Qt Creator 4.6.x (Based on Qt 5.11.x) APT list: apt-transport-https ...

  6. Layui项目实战干货总结(精品)

    写代码时遇到的知识点拿出来分享. 1.layer弹出层显示在top顶层 // 监听工具条 table.on('tool(tb-book)', function (obj) { var data = o ...

  7. zynq7000 I2C RTC 与 串口使用

    RS485 串口 测试 硬件上2路串口,其中UART 1对应PS STD IN/OUT,UART 0对应RS485: 图 ‑1 RS485电路,自动转换输入.输出方向 可参考 https://blog ...

  8. 使用Xilinx MIG验证硬件DDR设计

    1     导读 MIG 是xilinx的memory控制器,功能强大,接口易用.当硬件设计在设计对应的DDR接口时,最好先用MIG去配置一遍DDR的管脚约束.电平约束,从而避免硬件设计好了,实际却无 ...

  9. 【Azure 环境】标准版 Logic App 如何查看 Workflow的执行成功数和失败数的指标呢?

    问题描述 在Azure中创建逻辑应用(Logic App),有两种计划类型.一是消费型,另一种是标准型. 在消费型的Logic App Metrics页面中,我们可以看见Workflow的执行成功数指 ...

  10. 【Azure 微服务】Service Fabric 部署时遇见了VMExtensionProvisioningError错误: Multiple VM extensions failed to be provisioned on the VM

    问题描述 Deployment  Azure Service Fabric 时,遇见了VMExtensionProvisioningError, 全文如下: Deployment Name: 385A ...