php守护进程热更新,服务器编程--守护进程

守护(Daemon)进程又叫作“精灵进程”,虽然守护进程这个名字更为常用,但是个人感觉还是精灵进程较为机灵可爱些。服务器进程一般都是守护进程,这类进程的一个显著特点就是无交互地在后台进程。注意:这里所说的无交互并不是说真的不能和这类进程打交道,不能控制其运行,那样他们还能提供什么服务?而是说不能通过传统的终端用类似shell的交互方式控制其运行。

那么怎么创建守护进程呢?咋们就边看代码边讲解。

1

2  #include 3  #include 4  #include 5  #include 6  #include 7  #include 8  #include 9  #include 10  #include 11  #include 12  #include 13  #include 14  #include 15

1-15行: 加载必要的头文件,其实这些头文件并不是随意罗列的,而是当需要时再添加,具体方法是需要调用某个库函数或者系统调用时,用man查找它被定义的头文件的路径,然后添加之。如果在编译的时候显示某个函数没有被定义的错误,这时也可以用man查找所需的头文件之所在。有的时候甚至需要用grep到/usr/include目录下面查找变量或者函数的定义。

16  void daemonize(const char *prgname, ...)

17  {

18          va_list args;

19          char buf[512];

20          int pid, i;

21          struct sigaction act, oldact;

22          struct rlimit lim;

23

24          /* Detach controlling terminal */

25          if ((pid = fork()) < 0)

26                  exit(1);

27          else if (pid > 0)

28                  _exit(0);

29          setsid();

30

25-29行:从当前进程fork出一个子进程,然后当前进程退出。如果当前进程是shell从前台启动的的话,当当前进程退出的时候,子进程将变成孤儿进程,接着自动被启动进程(init)收养,当然它所在的进程组也将从前台转为后台。调用完setsid()之后,子进程将创建一个新的会话和进程组,sid和gpid都是子进程的pid,因为子进程已经和当前进程不属于一个会话,那么与会话相关联的控制终端也不复存在。如果你足够细心,你可能注意到了这段代码中用了两个进程退出函数exit和_exit,为什么要如此呢?_exit并不会执行由atexit或者on_exit注册的进程退出回调函数,除此之外,它和exit并没有区别。假设用户在调用daemonize把当前进程守护化之前注册过进程退出回调函数,如果fork成功而当前进程通过调用exit退出,那么回调函数将被执行,而这时执行回调函数也许是不当的,因为子进程并没有退出,当子进程退出的时候也许还将执行一遍回调函数。exit和_exit的选用正是为了保证进程退出回调函数被且尽被执行一次。以下对exit和_exit的选用也是基于此目的,遇到时将不再赘述。事实上,daemonize函数应该尽早调用,最好不要再其前面做太多的非必要操作,类似注册进程退出回调函数的举动应该尽量避免。

31          /* Avoid owning controlling terminal again */

32          memset(&act, 0, sizeof(act));

33          act.sa_handler = SIG_IGN;

34          sigemptyset(&act.sa_mask);

35          sigaction(SIGHUP, &act, &oldact);

36          if ((pid = fork()) < 0)

37                  exit(1);

38          else if (pid > 0)

39                  _exit(0);

40          /* Wait for the death of it's parent. */

41          while (getppid() != 1)

42                  ;

43          sigaction(SIGHUP, &oldact, NULL);

44

31-43行:这段代码的意义何在呢?有些UNIX操作系统(如SVR4)的会话首进程打开一个终端设备时,如果其所在会话组并没有控制终端,那么这个终端设备将自动成为这个会话组的控制终端。通过这次的fork而产生的孙子进程因为不是会话首进程,也就失去了为此会话设置控制终端的能力。当会话首进程退出的时候可能向其所在会话组的所有进程发送SIGHUP信号,而SIGHUP信号的默认处理函数是结束进程。为了防止孙子进程因此意外结束,忽略SIGHUP信号直到子进程退出,孙子进程被启动进程(init)收养。我查看了Linux内核的相关代码,发现只有当进程被SIGSTP终止时才会被发送SIGHUP和SIGCONT信号,所以此段关于信号的处理部分在Linux下是无效的,也许其他操作系统行为有异,姑且加之。

45          /* Deal with file operations */

46          umask(0);

47          if (chdir("/") < 0)

48                          exit(1);

49          if (getrlimit(RLIMIT_NOFILE, &lim) < 0)

50                  exit(1);

51          if (lim.rlim_cur == RLIM_INFINITY)

52                  lim.rlim_cur = 1024;

53          for (i = 0; i < lim.rlim_cur; i ++) {

54                  if (close(i) < 0 && errno != EBADF)

55                          exit(1);

56          }

57          if (open("/dev/null", O_RDWR) < 0

58                          || dup(0) < 0

59                          || dup(0) < 0)

60                  exit(1);

61

45-60行:设置文件掩码为0,改变当前工作目录到系统根目录,关闭所有打开的文件描述符,并把标准输入、标准输出和标准错误输出重定向到空设备(/dev/null),使他们保持沉默。

62          /* Ignore all traditional signals */

63          for (i = 1; i < 32; i ++)

64                  sigaction(i, &act, NULL);

65

62-65行:忽略所有的传统信号,当然SIGKILL信号是无法忽略的,所以我也没有检查返回值。按照设计惯例:SIGHUP用来热更新系统配置;SIGTERM用来结束进程,这个信号一般是需要捕捉并处理的,不然被SIGKILL强制杀死的滋味可不好受哦。(修正:62-65行的操作最好免除,因为大部分信号是不希望被忽略的,如SEGV)。

66          /* Initialize the log file */

67          va_start(args, prgname);

68          vsnprintf(buf, sizeof(buf), prgname, args);

69          va_end(args);

70          openlog(buf, LOG_CONS | LOG_PID, LOG_DAEMON);

71  }

72

66-71行:一般的服务器都需要用日志(log)记录守护进程的状态等信息以备分析和调试之用,这段代码就是打开到系统日志服务器(syslogd)的连接,并设置记录守护进程的进程名和pid。

至此,进程的守护化就顺利完成了。

服务器程序一般都具有排他性,换句话说就是一个操作系统上只允许有一个守护进程实例存在。以下代码实现了这个功能:

96 int uniqued(const char *prgname)

97 {

98         char buf[512];

99         int fd, retval = -1;

100

101         assert(prgname != NULL);

102         snprintf(buf, sizeof(buf), "/var/run/%s.pid", prgname);

103         if ((fd = open(buf, O_RDWR | O_CREAT)) < 0)

104                 goto out;

105         if (flock(fd, LOCK_EX | LOCK_NB) < 0) {

106                 if (errno == EWOULDBLOCK)

107                         retval = 0;

108                 else

109                         unlink(buf);

110                 goto err;

111         }

112         if (ftruncate(fd, 0) < 0)

113                 goto err;

114         snprintf(buf, sizeof(buf), "%ld\n", (long)getpid());

115         if (write(fd, buf, strlen(buf)) != strlen(buf))

116                 goto err;

117         retval = fd;

118

119 out:

120         return retval;

121

122 err:

123         while (close(fd) < 0 && errno == EINTR)

124                 ;

125         goto out;

126 }

遵从惯例,记录有守护进程进程号的文件被放在/var/run/目录下,并被命名为:守护进程名.pid。函数uniqued利用排他文件锁保证了守护进程实例的单一性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/410956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打开eclipse出现JVM terminated.Exit Code=-1错误的解决办法

&#xff30;&#xff33;&#xff1a;还有一种情况就是&#xff2a;&#xff36;&#xff2d;版本号太低&#xff0c;这个要重新安装后将&#xff2a;&#xff24;&#xff2b;目录置于&#xff4f;&#xff52;&#xff41;&#xff43;&#xff4c;&#xff45;前面&#xf…

【期外】 (一)关于LSH :局部敏感哈希算法

LSH是我同学的名字&#xff0c;平时我会亲切的称呼他为离骚&#xff0c;老师好&#xff0c;左移&#xff08;leftshift&#xff09;&#xff0c;小骚骚之类的&#xff0c;最近他又多了一个新的外号&#xff1a;局部敏感哈希&#xff08;Locally sensitive hashing)。 好了&…

java 数据库连接实例,Java连接各种数据库的实例

Java连接各种数据库的实例1、Oracle8/8i/9i数据库(thin模式)以下为引用的内容&#xff1a;Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();String url"jdbc:Oracle:thin:localhost:1521:orcl";//orcl为数据库的SIDString user"test…

python2和python3解释器的区别

python2和python3解释器的区别 1.input的区别 Python2中有raw_input和input. 他的raw_input就相当于Python3中的input,他们把用户输出的数据全部转化为str字符串类型. 他的input让用户输出的是用户输出数据的原始类型,用户输入int类型,他显示的也是int类型,以此类推 2.整型的区…

用于主题检测的临时日志(c48534c5-686f-461e-811f-a15a2f265756 - 3bfe001a-32de-4114-a6b4-4005b770f6d7)...

这是一个未删除的临时日志。请手动删除它。(34a657d4-0fcd-421a-9d75-e80f31602ac5 - 3bfe001a-32de-4114-a6b4-4005b770f6d7)转载于:https://www.cnblogs.com/wangshuai/archive/2010/07/31/1789347.html

mysql n 存储结构,MySQL体系结构和存储引擎概述

一、定义数据库和实例数据库&#xff1a;物理操作系统文件或其他形式文件类型的集合。数据库文件可以是frm、MYD、ibd 结尾的文件。从概念上来说&#xff0c;数据库是文件的集合&#xff0c;是依照某种数据模型组织起来并存放于二级存储器的数据集合&#xff1b;实例&#xff1…

常见排序查询算法Java代码实现

1. 排序算法代码实现 /*** ascending sort* 外层循环边界条件&#xff1a;总共需要冒泡的轮数--每一轮都将最大或最小的数冒泡到最后* 内层循环边界条件&#xff1a;冒泡数字移动的边界--最终数字需冒泡到此处* 时间复杂度&#xff1a;O(n^2)* param arr*/ public static vo…

java jsp 传递参数的方法,jsp传参方法小结

一、jsp页面到jsp页面##1.从a.jsp传递//将参数值为aaa&#xff0c;参数名test的参数传递到b.jsp页面中2.在b.jsp接收System.out.println("test的值是"test); %>二、jsp页面到servlet##1.首先需要新建一个Servlet&#xff0c;包的层次结构如下&#xff1a;demo--sr…

工作403-修改input里面的文本框值

1.style中需要作如下修改<style>input::-webkit-input-placeholder {/* placeholder颜色 */color: #aab2bd;/* placeholder字体大小 */font-size: 12px;} </style>2.HTML中的代码如<input type"text" placeholder"输入你想要查找的内容" …

Microsoft Expression Studio 4 Ultimate 中文版发布

Expression Studio Ultimate 是供生成网站以及 Windows 客户端应用程序和丰富媒体内容的专业设计人员使用的一系列工具&#xff0c;可以将创作人员引领到一个全新的创作天地。无论您是准备设计基于标准的网站&#xff0c;还是设计内容精美&#xff0c;令人赏心悦目的桌面或者 S…

Struts2基础

1.Struts2 Actions动作 Actions是Struts2框架的核心&#xff0c;因为它们适用于任何MVC&#xff08;Model View Controller&#xff09;框架。 每个URL映射到特定的action&#xff0c;其提供处理来自用户的请求所需的处理逻辑。但action还有另外两个重要的功能。 首先&#xf…

工作404-判断浏览器函数

// 判断浏览器函数if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {} else {window.location.href "../product_new.html&qu…

WebService简单示例

记录一下&#xff0c;以备后用&#xff1a;代码usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Web;usingSystem.Web.Services;usingSystem.Web.Services.Protocols;namespaceNiunan.ZZ.JKDA.Web.webservice{ ///<summary>///GGService 的…

php server 性能,PHP中:$_SERVER[‘REQUEST_TIME’]和 time()有什么区别,那个性能快!...

简单的说time()与$_SERVER["REQUEST_TIME"]都是获得时间的&#xff0c;但time返回当前的 Unix 时间戳而$_SERVER["REQUEST_TIME"]得到请求开始时的时间戳&#xff0c;稍有区别。1. time() 获取当前的系统时间戳inttime( void ) :返回自从 Unix 纪元(格林威…

Delphi捕捉DLL执行所抛出的异常。

先来说一下我如何写我的Dll文件的。 先看代码&#xff1a; 代码 librarypub_form;usesSysUtils, Classes, Windows, Forms, Parameter_Object, frm_LoginU in..\公用库单元\frm_LoginU.pas{frm_Login}, pub_Event in..\公用库单元\pub_Event.pas, Dll_LIB_ConstU in..\公…

docker版本Mysql安装

docker部署mysql 1. 下载 [rootlocalhost my.Shells]# ./dockerStart.sh start or stop start Redirecting to /bin/systemctl start docker.service [rootlocalhost my.Shells]# docker pull mysql Using default tag: latest Trying to pull repository docker.io/library/…

matlab 左上角,matlab – 访问’uitable`的左上角

在uitable中,我想访问行标签上方的单元格以及列标签的左侧.我想在该领域加上一些文字.可以这样做吗&#xff1f;最佳答案 简短的回答是肯定的,但这有点痛苦.您可以添加文本uicontrol并正确定位.一个功能的例子&#xff1a;% Dummy figure and tablef figure;d gallery(intege…

eclipse MyEclipse中安装 spket插件 js文件内容字体变小解决方案

在 eclipse 、 MyEclipse 中用 Spket 插件打开 js 文件后&#xff0c;发现字体非常小。&#xff08;在每次重启eclipse时会出现&#xff09;这个时候你只需要找到 Window->General->Appearance->Colors and Fonts ->Basic-Text Font ,点击右边的change&…