当前位置:首页 » 网页前端 » 怎样编写一个文件守护进程脚本
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

怎样编写一个文件守护进程脚本

发布时间: 2023-05-25 09:45:00

① 如何编写Linux Daemon后台程序

守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期核瞎模性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进 程。Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任 务。比如,作业规划进程crond,打印进程lpd等。 x0dx0a守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix环境下守护进程的编程规则并不一致。这需要读者注意,照搬 某些书上的规则(特别是BSD4.3和低版本的System V)到Linux会出现错误的。下面将全面介绍Linux下守护进程的编程要点并给出详细实例。 x0dx0a一. 守护进程及其特性 x0dx0a守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的 文件描述符,控制终端,会话和进程组,工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。最后,守 护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动,可以由作业规划进程crond启动,还可以由用户终端 (通常是shell)执行。 x0dx0a总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。如果读者对进程有比较深入的认识就更容易理解和编程了。 x0dx0a二. 守护进程的编程要点 x0dx0a前面讲过,不同Unix环境下守护进程的编程规则并不一致。所幸的是守护进程的编程原则其实都一样,区别在于具体的实现细节不同。这个原则就是要满足守护 进程的特性。同时,Linux是基于Syetem V的SVR4并遵循Posix标准,实现起来与BSD4相比更方便。编程要点如下; x0dx0a1. 在后台运行。 x0dx0a为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。改缓 x0dx0aif(pid=fork()) x0dx0aexit(0);//是父进程,结束父进程,子进程继续 x0dx0a2. 脱离控制终端,登录会话和进程组 x0dx0a有必要先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。 x0dx0a控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第1点的基础上,调用setsid()使进程成为会话组长: x0dx0asetsid(); x0dx0a说明:当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。 x0dx0a3. 禁止进程重新打开控制终端 x0dx0a现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端: x0dx0aif(pid=fork()) x0dx0aexit(0);//结束第一子进程,第二子进程继续(第二子进程不再是会话组长) x0dx0a4. 关闭打开的文件描述符 x0dx0a进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关神郑闭它们: x0dx0afor(i=0;i 关闭打开的文件描述符close(i);> x0dx0afor(i=0;i< NOFILE;++i)x0dx0a5. 改变当前工作目录 x0dx0a进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心,写运行日志的进程将工作目录改变到特定目录如/tmpchdir("/") x0dx0a6. 重设文件创建掩模 x0dx0a进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0); x0dx0a7. 处理SIGCHLD信号 x0dx0a处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为 僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将 SIGCHLD信号的操作设为SIG_IGN。 x0dx0asignal(SIGCHLD,SIG_IGN); x0dx0a这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程。 x0dx0a三. 守护进程实例 x0dx0a守护进程实例包括两部分:主程序test.c和初始化程序init.c。主程序每隔一分钟向/tmp目录中的日志test.log报告运行状态。初始化程序中的init_daemon函数负责生成守护进程。读者可以利用init_daemon函数生成自己的守护进程。 x0dx0a1. init.c清单 x0dx0a#include < unistd.h > x0dx0a#include < signal.h > x0dx0a#include < sys/param.h > x0dx0a#include < sys/types.h > x0dx0a#include < sys/stat.h > x0dx0avoid init_daemon(void) x0dx0a{ x0dx0aint pid; x0dx0aint i; x0dx0ax0dx0aif(pid=fork()) x0dx0aexit(0);//是父进程,结束父进程 x0dx0aelse if(pid< 0) x0dx0aexit(1);//fork失败,退出 x0dx0a//是第一子进程,后台继续执行 x0dx0ax0dx0asetsid();//第一子进程成为新的会话组长和进程组长 x0dx0a//并与控制终端分离 x0dx0aif(pid=fork()) x0dx0aexit(0);//是第一子进程,结束第一子进程 x0dx0aelse if(pid< 0) x0dx0aexit(1);//fork失败,退出 x0dx0a//是第二子进程,继续 x0dx0a//第二子进程不再是会话组长 x0dx0ax0dx0afor(i=0;i< NOFILE;++i)//关闭打开的文件描述符 x0dx0aclose(i); x0dx0achdir("/tmp");//改变工作目录到/tmp x0dx0aumask(0);//重设文件创建掩模 x0dx0areturn; x0dx0a} x0dx0a2. test.c清单 x0dx0a#include < stdio.h > x0dx0a#include < time.h > x0dx0avoid init_daemon(void);//守护进程初始化函数 x0dx0amain() x0dx0a{ x0dx0aFILE *fp; x0dx0atime_t t; x0dx0ainit_daemon();//初始化为Daemon x0dx0awhile(1)//每隔一分钟向test.log报告运行状态 x0dx0a{ x0dx0asleep(60);//睡眠一分钟 x0dx0aif((fp=fopen("test.log","a")) >=0) x0dx0a{ x0dx0at=time(0); x0dx0afprintf(fp,"I'm here at %sn",asctime(localtime(&t)) ); x0dx0afclose(fp); x0dx0a} x0dx0a} x0dx0a} x0dx0a以上程序在RedHat Linux6.0下编译通过。步骤如下: x0dx0a编译:gcc _g _o test init.c test.c x0dx0a执行:./test x0dx0a查看进程:ps _ef x0dx0a从输出可以发现test守护进程的各种特性满足上面的要求。

② 怎么写一个简单的守护进程

守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。他们常常在系统引导装入时启动,在系统关闭时终止。unix系统有很多守护进程,大多数服务器都是用守护进程实现的。比如,网络服务inetd、Web服务http等。同时,守护进程完成许多系统任务。比如,作业规划进程crond、打印进程lqd等。这里主要说明守护进程的进程结构,以及如何编写守护进程程序。因为守护进程没有控制终端,所以我们还要介绍在守护进程运行时错误输出的方法。
守护进程及其特性
守护进程最重要的特性是后台运行。在这一点上,DOS下的常驻内存程序TSR与之相似。其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等。这些环境通常是守护进程从执行它的父进程肢丛或(特别是shell)中继承下来的。最后,守护进程的启动方式有其特殊之处。它可以在系统启动时从启动脚本/etc/rc.d中启动,可以由inetd守护进程启动,可以有作业规划进程crond启动,还可以由用户终端(通常是shell)执行。总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普历伍通进程按照上述的守护进程的特性改造成为守护进程。如果大家对进程的认识比较深入,就对守护进程容易理解和编程了。
首先我们来察看一些常用的系统守护进程,看一下他们和几个概念:进程组、控制终端和对话期有什么联系。p s命令打印系统中各个进程的状态。该命令有多个选择项,有关细节请参考系统手册。为了察看所需的信息,执行:ps –axj
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 0 0 ? -1 S 0 0:04 init
1 2 1 1 ? -1 SW 0 0:00 [keventd]
1 3 1 1 ? -1 SW 0 0:00 [kapm-idled]
0 4 1 1 ? -1 SWN 0 0:00 [ksoftirqd_CPU0]
0 5 1 1 ? -1 SW 0 0:00 [kswapd]
0 6 1 1 ? -1 SW 0 0:00 [kreclaimd]
0 7 1 1 ? -1 SW 0 0:00 [bdflush]
0 8 1 1 ? -1 SW 0 0:00 [kupdated]
1 9 1 1 ? -1 SW< 0 0:00 [mdrecoveryd]
1 17 1 1 ? -1 SW 0 0:02 [kjournald]
1 92 1 1 ? -1 SW 0 0:00 [khubd]
1 573 573 573 ? -1 S 0 0:03 syslogd -r -x
1 578 578 578 ? -1 S 0 0:00 klogd -2
1 598 598 598 ? -1 S 32 0:00 portmap
进程号为1、2的这些进程非常特殊,存在于系统的整个生命期中。它们没有父进程ID ,没有组进程ID ,也没有对话期ID 。syslogd 守护进程可用于任何为操作人员记录系统消息的程序中。可以在一台实际的控制台上打印这些消息,也可将它们写到一个文件中。sendmail 是标准邮递守护进程。update 程序定期将内核缓存中的内容写到硬盘上(通常是每隔30 秒)。为了做到这一点,该程序每隔30 秒调用sync(2 )函数一次。cron 守护进程在指定郑首的日期和时间执行指定的命令。许多系统管理任务是由cron 定期地使相关程序执行而得以实现的。inetd进程监听系统的网络界面,以输入对各种网络服务器的请求。最后一个守护进程,lpd 处理对系统提出的各个打印请求。
注意,所有守护进程都以超级用户(用户ID为0)的优先权运行。没有一个守护进程具有控制终端,终端名称设置为问号(?)、终端前台进程组ID设置为-1。缺少控制终端是守护进程调用了setsid的结果。除update以外的所有守护进程都是进程组的首进程,对话期的首进程,而且是这些进程组和对话期中的唯一进程。最后,应当引起注意的是所有这些守护进程的父进程都是init进程。
在接触实际编程前,我们来看看编写守护进程要碰到的概念:进程组合会话期。
进程组
每个进程除了有一进程ID之外,还属于一个进程组(在讨论信号时就会涉及进程组)进程组是一个或多个进程的集合。每个进程有一个唯一的进程组ID。进程组ID类似于进程ID——它是一个正整数,并可存放在pid_t数据类型中。
每个进程组有一个组长进程。组长进程的标识是,其进程组ID等于其进程ID,进程组组长可以创建一个进程组,创建该组中的进程,然后终止,只要在某个进程组中有一个进程存在,则该进程就存在,这与其组长进程是否终止无关。从进程组创建开始到其中最后一个进程离开为止的时间区间称为进程组的生命期。某个进程组中的最后一个进程可以终止,也可以参加另一进程组。
前面已经提到进程调用setgid可以参加一个现存的组或者创建一个新进程组(setsid也可以创建一个新的进程组,后面将用到)
会话期
会话期(session)是一个或多个进程组的集合。其中,在一个会话期中有3个进程组,通常是有shell的管道线将几个进程编成一组的。
下面说明有关会话期和进程组的一些特性:
一个会话期可以有一个单独的控制终端(controlling terminal),这一般是我们在其上登录的终端设备(终端登录)或伪终端设备(网络登录),但这个控制终端并不是必需的。
建立与控制终端连接的会话期首进程,被称之为控制进程(contronlling process)。以及一个会话期中的几个进程组可被分为一个前台进程组(foreground process group)以及一个或几个后台进程组(background process group)
如果一个会话期有一个控制终端,则它有一个前台进程组,其他进程组为后台进程组。无论何时键入中断键(常常是delete或ctrl-c)或退出键(通常是ctrl-/),就会造成将中断信号或退出信号送至前途进程组的所有进程。
守护进程的编程规则
在不同Unix环境下,守护进程的具体编程细节并不一致。但所幸的是,守护进程的编程原则其实都一样,区别仅在于具体的实现细节不同,这个原则就是要满足守护进程的特性。编程规则如下:
1、在后台运行
为避免挂起控制终端,要将daemon放入后台执行,其方法是,在进程中调用fork使父进程终止,让daemon在子进程中后台执行。具体就是调用f o r k ,然后使父进程e x i t 。这样做实现了下面几点:
第一,如果该精灵进程是由一条简单s h e l l 命令起动的,那么使父进程终止使得s h e l l 认为这条命令已经执行完成。
第二,子进程继承了父进程的进程组I D ,但具有一个新的进程I D ,这就保证了子进程不是一个进程组的首进程。这对于下面就要做的s e t s i d 调用是必要的前提条件。
2、脱离控制终端,登录会话和进程组
登录会话可以包含多个进程组,这些进程组共享一个控制终端,这个控制终端通常是创建进程的登录终端、控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。
其方法是在第一点的基础上,调用setsid()使进程成为会话组长:
需要说明的是,当进程是会话组长时,setsid()调用会失败,但第一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离,由于会话过程对控制终端的独占性,进程同时与控制终端脱离。
具体是操作就是:
(a )成为新对话期的首进程
(b )成为一个新进程组的首进程
(c )没有控制终端。
3、禁止进程重新打开控制终端
现在,进程已经成为无终端的会话组长,但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:
4、关闭打开的文件描述符
进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在地文件系统无法卸下以及无法预料的错误。一般来说,必要的是关闭0、1、2三个文件描述符,即标准输入、标准输出、标准错误。因为我们一般希望守护进程自己有一套信息输出、输入的体系,而不是把所有的东西都发送到终端屏幕上。调用fclose();
5、改变当前工作目录
将当前工作目录更改为根目录。从父进程继承过来的当前工作目录可能在一个装配的文件系统中。因为精灵进程通常在系统再引导之前是一直存在的,所以如果精灵进程的当前工作目录在一个装配文件系统中,那么该文件系统就不能被拆卸。另外,某些精灵进程可能会把当前工作目录更改到某个指定位置,在此位置做它们的工作。例如,行式打印机假脱机精灵进程常常将其工作目录更改到它们的s p o o l 目录上。
可以调用chdir(“目录”);
6、重设文件创建掩码
将文件方式创建屏蔽字设置为0 。由继承得来的文件方式创建屏蔽字可能会拒绝设置某些许可权。例如,若精灵进程要创建一个组可读、写的文件,而继承的文件方式创建屏蔽字,屏蔽了这两种许可权,则所要求的组可读、写就不能起作用。
7、处理SIGCHLD 信号
处理SIGCHLD信号并不是必需的。但对于某些进程,特别是服务器进程往往在请求到来时生产子进程出来请求。如果父进程不等待子进程结束,子进程将成为僵尸进程,(zombie)而仍占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在系统V下可以简单的将SIGCHLD信号的操作设为SIG-IGN:
signal(SIGCHLD,SIG_IGN);
这样,内核在子进程结束时不会产生僵尸进程,这一点与BSD4不同,在BSD4下必须显示等 待子进程结束才能释放僵尸进程。
守护进程实例
守护进程实例包括两部分:主程序test.c和初始化程序init.c。主程序每隔一分钟向/tmp目录中的日志test.log 报告运行状态。初始化程序中的init_daemon 函数负责生成守护进程
void make_daemon(void)
{
pid_t pid;
FILE * lockfd;
sigset_t sighup;
int i;
extern pid_t getsid(pid_t);
pid = fork();//第一个子进程生成
if (pid < 0) {
printinfo("fork error!",INFOERROR);
exit(FAILEXIT);
}else if (pid > 0) {
printinfo("fork 1 ok! ", INFOSCREEN);
exit(OKEXIT);//退出父进程,摆脱shell的控制
}
pid = getpid();//获得子进程自身的id
lockfd = fopen(PIDFILE, "w");//以下是将pid写入文件
if (lockfd != NULL) {
fprintf(lockfd, "%d/n", pid);
fclose(lockfd);
}//写入pid
if (getsid(0) != pid) {//创建新的会话期
if (setsid() < 0) {
printinfo("backupdaemon setsid error!",INFOERROR);
perror("setsid");
}
}
if(pid=fork()){//再次生成子进程,这时候是孙子进程
exit(0);//退出上一代进程
}else if(pid<0){
exit(1);
}
close(1);//关闭文件
close(2);
chdir(rundir);//改变运行的目录
umask(022);//改变文件权限
}
守护进程的错误输出守护进程不属于任何终端,所以当需要输出某些信息时,它无法像一般程序那样将信息直接输出到标准输出和标准错误输出中。我们很大时候也不希望每个守护进程将它自己的出错消息写到一个单独的文件中。因为对于系统管理人员而言,要记住哪一个守护进程写到哪一个记录文件中,并定期的检查这些文件,他一定会为此感到头疼的。所以,我们需要有一个集中的守护进程出错记录机制。目前很多系统都引入了syslog记录进程来实现这一目的。自伯克利开发了BSD syslog并广泛应用以来,BSD syslog 机制被大多数守护进程所使用。我们下面介绍BSD syslog 的用法。有三种方法产生记录消息:
1 内核例程可以调用log函数。任何一个用户进程通过打开和读/dev/klog设备就可以读取这些消息。因为我们无意编写内核中的例程,所以不再进一步说明此函数。
2 大多数用户进程(守护进程)调用syslog函数以产生记录消息。我们将在下面说明其调用序列。这使消息发送至Unix域数据报套接口/dev/log。
3 在此主机上,或通过TCP/IP网络连接到此主机的某一其他主机上的一个用户进程可将记录消息发向UDP端口514。注意:syslog 函数并不产生这些UDP数据报——它们要求产生此记录消息的进程具有显式的网络编程。通常,syslog守护进程读取三种格式的记录消息。此守护进程在启动时读一个配置文件。一般来说,其文件名为/etc/syslog.conf,该文件决定了不同种类的消息应送向何处。例如,紧急消息可被送向系统管理员(若已登录),并在控制台上显示,而警告消息则可记录到一个文件中。该机制提供了syslog函数,其调用格式如下
#include
void openlog (char*ident,int option ,int facility);
void syslog(int priority,char*format,……)
void closelog();
调用openlog是可选择的。如果不调用openlog,则在第一次调用syslog时,自动调用openlog。调用closelog也是可选择的,它只是关闭被用于与syslog守护进程通信的描述符。调用openlog 使我们可以指定一个ident,以后, 此ident 将被加至每则记录消息中。ident 一般是程序的名称(例如 ,cron ,inetd 等)。option 有4种可能:LOG_CONS 若日志消息不能通过Unix域数据报发送至syslog,则将该消息写至控制台。LOG_NDELAY1 立即打开Unix域数据报套接口至syslog守护进程,而不要等到记录第一消息。通常,在记录第一条消息之前,该套接口不打开。LOG_PERROR 除将日志消息发送给syslog 外,还将它至标准出错。此选项仅由4.3BSDReno及以后版本支持。LOG_PID 每条消息都包含进程ID。此选项可供对每个请求都fork一个子进程的守护进程使用。在openlog中设置facility参数的目的是让配置文件可以说明,来自不同设施的消息以不同的方式进行处理。如果不调用openlog,或者以facility 为0来调用它,那么在调用syslog 时,可将facility作为priority参数的一个部分进行说明。调用syslog产生一个记录消息。其priority参数是facility和level的组合,它们可选取的值分别列于下面。level值按优先级从高级到最低按序排列

③ 如何将我的php脚本以守护进程的方式一直运行

public function init(){
$pid = pcntl_fork();
// 创建子进程失败
if ( $pid == -1 ) {
exit("error: start server fail. can not create process.\n");
} elseif ( $pid > 0 ) {
exit(0);//删除父进程,为下面脱离登录搜春会话和终端做准备
}

posix_setsid(); //使第一子进程成为新的会话组长和新的进程组长,脱离原来登录会话和终端控制,但是新的组长可以重开终端,所以需要在杀一次
$pid = pcntl_fork();
// 创建子进程失败
if ( $pid == -1 ) {
exit("error: start server fail. can not create process.\n"雀模);
} elseif ( $pid > 0 ) {
exit(0);
//杀死第一子进程,使第二子进程不在是会话组长,故不能重开终端,同时第二进程也脱离了原顷漏缓来父进程的登录会话和终端控制,最终成为一个守护进程
}

}

④ 如何将我的php脚本以守护进程的方式一直运行

写好php脚本。建议定期检测内存占用,核心逻辑就不写了。这个跟业务有关。
if(memory_get_usage()>100*1024*1024){
exit(0);//大于100M内存退出程序,防止内存泄漏被系统杀死导致任务终端
}

假设该php文件的路径为/root/run.php
打开终端
setsid php /root/run.php > /dev/null &

编辑进程监控脚本,当进程不存在时,自动重启 /root/monitor.sh
#!/bin/bash
alive=`ps aux|grep root\/run|grep -v grep|wc -l`
if [ $alive -eq 0]
then
php /root/run.php > /dev/null &
fi

添加计划任务(每分钟检测一次)
crontab -e
* * * * * /root/monitor.sh > /dev/null &

⑤ 如何在Linux下用c语言创建守护进程并监控系统运行期间的所有进程

可以分三步来做:


  1. 做两个简单的守护进程,并能正常运行

  2. 监控进程是否在运行

  3. 启动进程


综合起来就可以了,代码如下:
被监控进程thisisatest.c(来自):
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/param.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<time.h>


void init_daemon()
{
int pid;
int i;
pid=fork();
if(pid<0)
exit(1); //创建错误,退出
else if(pid>0) //父进程退出
exit(0);

setsid(); //使子进程成为组长
pid=fork();
if(pid>0)
exit(0); //再次退出,使进程不是组长,这样进程就不会打开控制终端
else if(pid<0)
exit(1);


//关闭进程打开的文件句柄
for(i=0;i<NOFILE;i++)
close(i);
chdir("/root/test"); //改变目录
umask(0);//重设文件创建的掩码
return;
}


void main()
{
FILE *fp;
time_t t;
init_daemon();
while(1)
{
sleep(60); //等待一分钟再写入
fp=fopen("testfork2.log","a");
if(fp>=0)
{
time(&t);
fprintf(fp,"current time is:%s ",asctime(localtime(&t))); //转换为本地时间输出
fclose(fp);
}
}
return;
}


监控进程monitor.c:
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/param.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<time.h>


#include<sys/wait.h>
#include<fcntl.h>
#include<limits.h>


#define BUFSZ 150


void init_daemon()
{
int pid;
int i;
pid=fork();
if(pid<0)
exit(1); //创建错误,退出
else if(pid>0) //父进程退出
exit(0);


setsid(); //使子进程成为组长
pid=fork();
if(pid>0)
exit(0); //再次退出,使进程不是组长,这样进程就不会打开控制终端
else if(pid<0)
exit(1);


//关闭进程打开的文件句柄
for(i=0;i<NOFILE;i++)
close(i);
chdir("/root/test"); //改变目录
umask(0);//重设文件创建的掩码
return;
}


void err_quit(char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}


// 判断程序是否在运行
int does_service_work()
{
FILE* fp;
int count;
char buf[BUFSZ];
char command[150];
sprintf(command, "ps -ef | grep thisisatest | grep -v grep | wc -l" );


if((fp = popen(command,"r")) == NULL)
err_quit("popen");


if( (fgets(buf,BUFSZ,fp))!= NULL )
{
count = atoi(buf);
}
pclose(fp);
return count;
// exit(EXIT_SUCCESS);
}




void main()
{
FILE *fp;
time_t t;
int count;
init_daemon();
while(1)
{
sleep(10); //等待一分钟再写入
fp=fopen("testfork3.log","a");
if(fp>=0)
{
count = does_service_work();
time(&t);
if(count>0)
fprintf(fp,"current time is:%s and the process exists, the count is %d ",asctime(localtime(&t)), count); //转换为本地时间输出
else
{
fprintf(fp,"current time is:%s and the process does not exist, restart it! ",asctime(localtime(&t))); //转换为本地时间输出
system("/home/user/daemon/thisisatest"); //启动服务
}


fclose(fp);
}
}
return;
}


具体CMD命令:


cc thisisatest.c -o thisisatest
./thisisatest
cc monitor.c -o monitor
./monitor


tail -f testfork3.log -- 查看日志

⑥ python 守护进程

一、守护进程的特性

守护进程是一个在后台运行并且不受任何终端控制的进程(守护进程独立于所有终端,之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的模袭睁信息也不在任何终端上显示。)

二、守护进程的作用

守护进程是一类在后台执行,生命周期较长的进程,它一般随系统启动运行,在系统关闭的时候停止。所以守护进程一般用作系统后台服务。

三、如何编写一个守护进程

编写守护进程实际上是把一个普通进程按照守护进程的特性进行改造。

守护进程的开发涉及到子进程、进程组、会晤期、信号量、文件权限、目录和控制终端等多个概念。

由于守护进程是脱离控制终端的,因此首先创建子进程,终止父进程,使得程序在shell终端里造成一禅敏个已经运行完毕的假象。之后所有的工作都在子进程中完成,而用户在shell终端里则可以执行其他的命令,从而使得旦岁程序以僵尸进程形式运行,在形式上做到了与控制终端的脱离。

四、python 编写守护进程

参考: https://cloud.tencent.com/developer/article/1411989

⑦ 如何使用QT创建一个Linux守护进程

写一段代码不断扫描你的守护的进程,发现挂了就启动。守护进程用脚本写更好。

⑧ 如何使shell脚本成为守护进程

1,if条件语句里面表达式要与左右[ ] 用空格隔开,否则运行时会报错
2,用表达式给变量负值时要将表达式放在括号()里面,并在前面加符号"$",应该还有其他方法 目前只会这种,在参考那篇博客用单引号运行无法通过。
3,ps aux | grep $PROGRAM | grep -v grep | wc -l 此表达式检测运行进程数量
4,ps aux | grep $PROGRAM | grep T | grep -v grep | wc -l 此表达式检测进程运行状态,0:运行 1:停止 但进程依然存在 可以通过命令 kill -SIGSTOP pid 进行测试
第一个条件判断目标进程运行数目 数目小于1即为0 则运行目标进程
第二条件判断目标进程是否处于停止状态 处于停止状态则kill掉 重新运行该进程
应用程序编译完及脚本编写好后,在/etc/rc.local 文件中添加执行语句 /usr/mytest/mytest.sh & 重启后就能自动加载守护进程了。

⑨ 如何将我的php脚本以守护进程的方式一直运行

用一个简单可靠的Shell脚本来守护一个可森首缓能会突芹凳发退出的此模PHP服务
/etc/rc.local 里加入开机启动命令:
nohup /path/to/swoole.sh >>/path/to/swoole.sh.log 2>&1 &
swoole.sh 内容如下:
#!/bin/sh
PREFIX=/home/eechen
INTERVAL=1
nohup php ${PREFIX}/swoole.php >>${PREFIX}/swoole.log 2>&1 & echo $! > ${PREFIX}/swoole.pid
while [ 1 ]; do
if [ ! -d /proc/`cat ${PREFIX}/swoole.pid` ]; then
nohup php ${PREFIX}/swoole.php >>${PREFIX}/swoole.log 2>&1 & echo $! > ${PREFIX}/swoole.pid
echo 'NEW_PID:'`cat ${PREFIX}/swoole.pid && date '+%Y-%m-%d %H:%M:%S'`
fi
sleep ${INTERVAL}
done

⑩ 如何正确编写linux守护进程

1、守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。如果想让某个进程不因为用户或终端或其他地变化而受到影响,那么就必须把这个进程变成一个守护进程。
2、创建守护进程步骤
1)创建子进程,父进程举液退出
之后的所有工作都在子进程中完成,而用户在Shell终端里则可以执行其他命令,从而在形式上做到了与控制终端的脱离。
在Linux中父进程先于子进程退出会造成子进程成为孤儿进程,而每当系统发现一个孤儿进程时,就会自动由1号进程(init)收养它,这样,原先的子进程就会变成init进程的子进程。
2)在子进程中创建新会话
进程组:是一个或多个进程的集合。进程组有进程组ID来唯一标识。除了进程号(PID)之外,进程组ID也是一个进程的必备属性。每个进程组都有一个组长进程,其组长进程的进程号等于进程组ID。且该进程组ID不会因组长进程的退出而受到影响。
会话周期:会话期是一个或多个进程组的集合。通常,一个会话开始于用户登录,终止于用户退出,在此期间该用户运行的所有进程都属于这个会话期。
(1)pid_t setsid(void);
setsid() creates a new session if the calling process is not a process group leader. The calling process will be the only process in this new process group and in this new session.
setsid函数用于创建一个新的会话,并担任该会话组的组长。调用setsid有下面的3个作用:
① 让进程摆脱原会话的控制
② 让进程摆脱丛答猜原进程组的控制
③ 让进程摆脱原控制终端的控制
有以下三个结果:
(a)成为新会话的首进程
(b)成为一个新进程组的组长进程
(c)没有控制终端。
有些人建议在此时再次调用fork,并使父进程终止。第二个子进程作为守护进程继续运行。这样就保证了该守护进程不是会话首进程。
setsid函数能够使进程完全独立出来,从而摆脱其他进程的控制。
setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。 子进程可以自己组成一个新的进程组,即调用setpgrp()与原进程组脱离关系,产生一个新的进程组,进程组号与它的进程号相同.这样,父进程退出运行后就不会影响子进程的当前运行.
3)改变当前目录为根目录
使用fork创建的子进程继承了父进程的当渗型前工作目录;进程活动时,其工作目录所在的文件系统不能卸下。通常的做法是让"/"作为守护进程的当前工作目录,也可以是其他目录,如/tmp,使用chdir。
4)重设文件权限掩码
文件权限掩码是指屏蔽掉文件权限中的对应位。比如,有个文件权限掩码是050,它就屏蔽了文件组拥有者的可读与可执行权限。mask = mask & ~050
通常,把文件权限掩码设置为0,umask(0)。
5)关闭文件描述符
用fork函数新建的子进程会从父进程那里继承已经打开了的文件描述符。这些被打开的文件可能永远不会被守护进程读写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下。
在上面的第二步之后,守护进程已经与所属的控制终端失去了联系。因此从终端输入的字符不可能达到守护进程,守护进程中用常规方法(如printf)输出的字符也不可能在终端上显示出来。所以,文件描述符为0、1和2 的3个文件(常说的输入、输出和报错)已经失去了存在的价值,也应被关闭。
for(i=0;i<MAXFILE;i++)
close(i);
6)守护进程退出处理
当用户需要外部停止守护进程运行时,往往会使用 kill命令停止该守护进程。所以,守护进程中需要编码来实现kill发出的signal信号处理,达到进程的正常退出。
signal(SIGTERM, sigterm_handler);
void sigterm_handler(int arg)
{
_running = 0;
}
7)处理SIGCHLD信号
处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将 SIGCHLD信号的操作设为SIG_IGN。
signal(SIGCHLD,SIG_IGN);
这样,内核在子进程结束时不会产生僵尸进程。