守护进程的单实例实现_非宁静无以致远_百度空间

守护进程的单实例实现_非宁静无以致远_百度空间

守护进程的单实例实现

为了正常工作,守护进程应该实现为单实例的,也就是在任一时刻只运行该守护进程的一个副本,因为这个守护进程要排它的访问一个设备。这里需要用到文件锁的机制,如果守护进程创建一个文件,并且在整个文件上加上一把锁,那就只允许创建一把这样的写锁,在此之后如果试图再创建一把这样的写锁就将失败,以此向续守护进程副本指明已经有一个副本正在运行。而这个锁文件通常都放在/var/run目录中,锁文件的名字通常是name.pid,其中name是此守护进程的名字。注意,守护进程可能需要有root权限才能在此目录下创建文件。

代码实现及分析:

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

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

//成功返回0,若有错误返回-1,错误原因存于errno。

int lockfile(int ff)
{
    struct flock fl;
    
    //l_type是设置锁定的状态。它有三种状态:F_RDLCK是建立一个供读取用的锁定;F_WRLCK是建立一个供写入用的锁定;F_UNLCK是删除之前建立的锁定。

fl.l_type = F_WRLCK;

//l_start是设置锁定区域的开头位置

fl.l_start = 0;

//l_whenec是决定l_start的位置。它有三种状态:SEEK_SET是以文件开头为锁定的起始位置;SEEK_CUR是以目前文件读写位置为锁定的起始位置;SEEK_END是以文件结尾为锁定的起始位置。

fl.l_whence = SEEK_SET;

//l_len是设置锁定区域的大小

fl.l_len = 0;
    //还有一个l_pid是设置锁定动作的进程

//fcntl()是唯一的符合POSIX标准的文件锁实现,所以也是唯一可移植的,功能比较强大。

//F_SETLK的作用:在l_whence、l_start、l_len等都设置好的情况下,如果l_type被设置为F_RDLCK或F_WRLCK就分配一个锁,如果l_type被设置为F_UNLCK就释放一个锁。如果失败就返回-1,并把errno的错误设为EACCES或EAGAIN。

return(fcntl(ff,F_SETLK,&fl));
}

void already_running(void)
{
    int fd;
    char buf[16]    ;

//此处的open是系统调用函数,第一个参数是打开的文件路径;第二个参数是对文件操作的权限,此处是可读写,可创建(如果文件不存在就会自动创建它);第三个参数是文件被创建后给文件的权限,比如S_IRUSR相当于400,权此用户有读权限。

fd = open(LOCKFILE,O_RDWR|O_CREAT,LOCKMODE);

if (fd < 0)
    {
        //strerror(),返回一个合适的string型的错误

syslog(LOG_ERR,"can't open %s: %s",LOCKFILE,strerror(errno));
        exit(1);
    }

if (lockfile(fd) < 0)
    {
        if (errno == EACCES || errno == EAGAIN)
        {
            close(fd);
            exit(1);
        }
         syslog(LOG_ERR,"can't lock %s: %s",LOCKFILE,strerror(errno));
        exit(1);
    }
    //把fd指定的文件大小改为0。参数fd为已打开的文件描述词,而且必须是以写入模式打开的文件。之所以要把文件长度截短为0,是因为上一个进程的ID字符串可以长于当前进程的ID字符串。

ftruncate(fd,0);

//把整型转换成字符串

sprintf(buf,"%d",getpid());

//把转换成字符串的进程ID号写入文件/var/run/*.pid中

write(fd,buf,strlen(buf));
}

int main(int argc,char *argv[])
{
//     time_t now;

int childpid,fd,fdtablesize;
//     int error,in,out;

int fp;
    
    //屏蔽一些有关控制终端操作的信号。防止在守护进程没有正常运转起来时,控制终端受到干扰退出或挂起,此处忽略了终端I/O信号、STOP信号

signal(SIGTTOU,SIG_IGN);
    signal(SIGTTIN,SIG_IGN);
    signal(SIGTSTP,SIG_IGN);
    signal(SIGHUP,SIG_IGN);

//由于子进程会继承父进程的某些特性,如控制终端、登录会话、进程组等,而守护进程最终要脱离控制终端到后台去运行,所以必须把父进程杀掉,以确保子进程不是进程组长,这也是成功调用setsid()所要求的。

if (fork() != 0)
    {
        exit(1);
    }
        
    //脱离了控制终端还要脱离登录会话和进程组,这里可以调用setsid()函数,调用成功后程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离,由于会话过程对控制终端的独占性,进程同时与控制终端脱离。

/*
     if (setsid() < 0)
     {
         exit(1);
     }
*/
    //要达到setsid()函数的功能也可以用如下处理方法。"/dev/tty"是一个流设备,也是终端映射,调用close()函数将终端关闭。

if ((fp=open("/dev/tty",O_RDWR)) >= 0)
    {
         ioctl(fp,TIOCNOTTY,NULL);
        close(fp);
    }

//进程已经成为无终端的会话组长,但它可以重新申请打开一个新的控制终端。可以通过不再让进程成为会话组长的方式来禁止进程重新打开控制终端,需要再次调用fork函数。

if (fork() != 0)
    {
        exit(1);
    }
    
    //从父进程继承过来的当前工作目录可能在一个装配的文件系统中。因为守护进程通常在系统重启之前是一直存在的,所以如果守护进程的当前工作目录在一个装配文件系统中,那么该文件系统就不能被卸载。比如说从父进程继承的当前目录是/mnt下面的一个被挂载的目录。

if (chdir("/tmp") == -1)
    {
        exit(1);
    }

//关闭打开的文件描述符,或重定向标准输入、标准输出和标准错误输出的文件描述符。进程从创建它的父进程那里继承了打开的文件描述符。如果不关闭,将会浪费系统资源,引起无法预料的错误。getdtablesize()返回某个进程所能打开的最大的文件数。

for (fd=0,fdtablesize=getdtablesize();fd<fdtablesize;fd++)
    {
        close(fd);
    }

//有的程序有些特殊的需求,还需要将这三者重新定向。

/*
     error=open("/tmp/error",O_WRONLY|O_CREAT,0600);
     dup2(error,2);
     close(error);
     in=open("/tmp/in",O_RDONLY|O_CREAT,0600);
     if(dup2(in,0)==-1) perror("in");
     close(in);
     out=open("/tmp/out",O_WRONLY|O_CREAT,0600);
     if(dup2(out,1)==-1) perror("out");
     close(out);
*/

//由继承得来的文件方式创建的屏蔽字可能会拒绝设置某些权限,所以要重新赋于所有权限。

umask(0);

//如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源,如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。因此需要对SIGCHLD信号做出处理,回收僵尸进程的资源,避免造成不必要的资源浪费。

signal(SIGCHLD,SIG_IGN);

//守护进程不属于任何终端,所以当需要输出某些信息时,它无法像一般程序那样将信息直接输出到终端,可以使用linux中自带的syslogd守护进程,它向用户提供了syslog()系统调用函数。信息都保存在/var/log/syslog文件中。

syslog(LOG_USER|LOG_INFO,"守护进程测试!\n");

//每隔60秒钟就向/var/log/syslog日志文件里写入一次syslog()发出的信息。

/*     while (1)
     {
         //time(time_t *t)返回从1970年1月1日0时0分0秒到现在的所有秒数。
         time(&now);
            
         //获得父进程ID和子进程ID。
         syslog(LOG_USER|LOG_INFO,"PPID: %d PID: %d\n",getppid(),getpid());

//ctime(const time_t *)返回当前时间的一个char型指针。
         syslog(LOG_USER|LOG_INFO,"当前时间:%s\n",ctime(&now));

//睡眠60秒
         sleep(60);
     }
*/
    while (1)
    {
         already_running();
        sleep(60);
    }
    return 0;
}

posted on 2013-02-28 18:16 lexus 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lexus/archive/2013/02/28/2937533.html

守护进程的单实例实现_非宁静无以致远_百度空间相关推荐

  1. 诗歌十一 十二则名门家训(非淡泊无以明志,非宁静无以致远)

    立身篇 1. 三国·诸葛亮<诸葛亮集> 夫君子之行,静以修身,俭以养德.非淡泊无以明志,非宁静无以致远. 夫学须静也,才须学也,非学无以广才,非志无以成学. 2. 宋·欧阳修<欧阳永 ...

  2. java用正则表达式判断字符串中是否仅包含英文字母、数字和汉字_灵思致远Leansmall的博客-CSDN博客_java判断字符串只包含数字字母

    import java.util.regex.Matcher; import java.util.regex.Pattern;public class StrValidate {// 纯数字priva ...

  3. 非淡泊无以明志,非宁静无以致远!

    诸葛孔明<戒子篇>"夫君子之行:静以修身,俭以养德.非淡泊无以明志,非宁静无以致远.  夫学须静也,才须学也.非学无以广才,非静无以成学.慆慢则不能研精,险燥则不能理性.   年 ...

  4. 非淡泊无以明志 非宁静无以致远

    取这个标题只是希望自己不要忘了这句话,下面狭义的叙述无法诠释它! 这是我周五零零碎碎想到的,也就这么写上来了. 最近总是被他人营造的环境所包围.高三了,有些人非要显示自己多有优势,没办法,自己技不如人 ...

  5. 非淡泊无以明志, 非宁静无以致远

    对于人生无深刻的体验者,不易知淡泊之难得可贵,不易知淡泊是有助于明志的.在洪应明看来,只有那些有着丰富的社会阅历.通晓人情世故而又尽尝人世的浓淡滋味者,才会认识放达无拘之可贵,才会知道淡泊有助于培植明 ...

  6. 如何免费获得可以升级的nod32官方中文版杀毒软件 - 非淡泊无以明志,非宁静无以致远。 - C++博客...

    正版杀毒软件下载: http://www.nod32cn.com/download/download.php 获得正版序列号地址: http://www.nod32club.com/partner/c ...

  7. 非宁静无以致远,非淡薄无以明志!

    从今天起,不再发表任何与技术无关的感想,任何嬉笑怒骂,皆置于脑后.让自己从一个平庸的人变成一个真正高尚的人,而不是仅仅只是一个高尚的想法.致力于在此写下每天的备课内容和培训日记,不再考虑原创与借鉴,自 ...

  8. java cms视频_领航致远JAVA CMS系统项目实战 视频+源码精品实战项目

    [课程内容] 01 CMS系统功能需求简介 02 如何采用用例分析方法来理解需求 03 后台管理系统用例 04 实现验证码的初步思路 05 生成验证码 06 判断验证码是否正确 07 返回登录页面时, ...

  9. oracle 王博 领航致远_《合欢宫记事》作者:最是一年明冬月

    Copyright © 2010-2020 盘多多如风搜百度云,就是哎哟喂啊百度网盘资源搜索. 此页面内容由计算机程序自动抓取自第三方公开免费站点,以非人工方式自动生成,只作交流和学习使用,本站不储存 ...

  10. Python实例浅谈之五Python守护进程和脚本单例运行

    一.简介 守护进程最重要的特性是后台运行:它必须与其运行前的环境隔离开来,这些环境包括未关闭的文件描述符.控制终端.会话和进程组.工作目录以及文件创建掩码等:它可以在系统启动时从启动脚本/etc/rc ...

最新文章

  1. C#中将结构类型数据存储到二进制文件中方法
  2. 南通大学python期末考试试卷答案_南通大学试卷A(答案及评分标准)
  3. Solr 5.4.0
  4. JZOJ 5426. 【NOIP2017提高A组集训10.25】摘Galo
  5. python算法与数据结构-数据结构中常用树的介绍
  6. 虚拟局域网Vlan与单臂路由、三层交换、链路聚合技术
  7. python自动化测试脚本可以测php吗_请对比分析一下php的自动化测试与python的自动化测试...
  8. 数据中台 画像标签_如何通过数据中台标签平台,圈出产品高价值用户?
  9. 英国政府将设立10亿英镑光网基金
  10. AI从业人员需要必备这些算法和工具!
  11. HTML +CSS 制作个人简历
  12. 模型预测控制的缺点_模型预测控制(MPC)与最优控制的理论分析 | NeurIPS 2020
  13. c++ fbxsdk安装配置_Linux上安装软件 - coydone
  14. 2020年日历电子版(打印版)_2020年日历全年表黄历-2020年日历打印版下载 A4横版带农历--pc6下载站...
  15. 如何设计一个秒杀系统(完整版)
  16. 电影“我是谁,没有绝对安全的系统“——黑客技术点评
  17. sql 语句实现电话号筛选,例如:AABB,ABAB
  18. odoo11 odoo.addons.base.ir.ir_model: Access Denied by ACLs for operation: read, uid: 4,
  19. 《Hexo: 从零开始编写自己的主题》1. Hexo概述以及Hexo工作原理
  20. 太阳能路灯的根本结构及作业原理

热门文章

  1. 背包问题(动态规划 C/C++)
  2. 联想s40-70进入bios方法。
  3. 把幽灵和熔断关闭_比较幽灵和三巨头
  4. Tomcat-幽灵猫GhostCat漏洞复现
  5. python打印九九乘法表上三角_用Python打印九九乘法表正三角和倒三角。
  6. [game]《泰坦陨落2》
  7. 【宝藏系列】如何解决word选中文字按backspace无法删除的问题
  8. mysql虚拟列表_动态网页制作-官方版合集下载-多特
  9. Ubuntu下vsftpd - 虚拟账户配置
  10. EfficientDet实验笔记