C++码农日记(全程视频讲解)
上QQ阅读APP看书,第一时间看更新

第11天 让程序在操作系统启动时自动运行

视频讲解

今天要学习的案例对应的源代码目录:src/chapter02/ks02_10。本案例不依赖第三方类库。程序运行效果如图2-61所示。

图2-61 第11天案例程序运行效果

今天的目标是掌握如下内容:如何让程序随操作系统自动启动。

在第9天、第10天,我们学习了怎样让程序以守护进程(后台服务)方式运行。程序在Windows、Linux上能够以服务方式启动之后,下一步就是让程序在操作系统启动后可以自动运行,这样可以有效减轻系统维护人员的负担。在很多情况下,程序所运行的机器一般都放置在专用机房的机架上,而且是长时间不间断运行,如果没有特殊情况,维护人员就无须进入机房。所以最简单的方式就是,维护人员为机器上电之后操作系统会自动启动,在操作系统启动之后,程序可以自动运行。这样就无须维护人员登录到桌面,因此可以省去维护人员登录操作系统桌面以及启动程序的工作。让进程在Windows中自动启动的方法比较简单,只要按照图2-58所示,将进程的【启动类型】设置为【自动】即可。在Linux上让进程自动启动可以使用脚本实现。这里分别编写两个脚本实现进程的启动。

(1)启动所有程序的脚本。这种脚本用来在开机时自动启动某个项目中所有需要运行的程序。有了这个脚本,只要机器一上电,用户就可以离开了,系统启动后会自动运行该脚本并自动启动所有程序。在另外一些情况下(如需要更换整套程序),当需要重新启动所有程序时也可以使用该脚本。

(2)启动单个程序的脚本。用来根据输入的参数启动指定的某个进程。

1.用来启动某个项目中所有程序的脚本

1)编写脚本process_manager.sh

在Linux系统中,为进程编写自启动脚本时需要先为进程设置运行环境,也就是设置环境变量。这是因为同一个机器中可能要运行不同的软件系统,而不同的软件系统之间的环境变量设置可能互相冲突(如将同一个环境变量设置为不同的值)。为了避免不同系统之间的运行环境相互影响,一个可取的方案是用脚本为各个软件系统单独设置运行环境。如代码清单2-21所示,该脚本文件名为process_manager.sh,它存放在本节对应的源代码目录中。如标号①处所示,“#!/bin/sh”是指此脚本使用/bin/sh来解释执行,“#!”是特殊的表示符,其后面跟的是解释此脚本的Shell的路径。如果需要对文件添加注释,可以使用#字符开头,见标号②处。从标号③处开始,为脚本中后续运行的进程设置环境变量。需要注意的是,进程启动时用到的所有环境变量都应该在这里设置,而且内容必须与用户从桌面登录后启动程序的环境变量一致,否则脚本无法成功将程序启动。在标号④处,定义一个函数kill_running(),当运行process_manager.sh stop以便关闭所有程序时,将会通过调用kill_running()来关闭指定进程。在脚本中定义函数跟在C++中定义函数类似,也需要把函数体写在{}中。从标号⑤处开始是脚本的核心功能代码,这里采用类似C语言中switch-case分支判断的方式进行处理,其中${1}表示执行脚本时输入的“参数1”,比如执行process_manager.sh start,那么${1}的值为start。如标号⑥处所示,用来处理start分支,也就是“参数1=start”,在本分支中,启动该项目的所有进程,并以两个分号“;;”结束该分支。如标号⑦处所示,在stop分支中,定义变量cmd=进程名,然后调用kill_running()来退出该进程。在标号⑧处,针对其他情况进行处理,这相当于default分支。esac表示case语句块的结束,见标号⑨处。在标号⑩处使用exit0表示脚本执行完毕且返回值为0。

代码清单2-21

2)将脚本移动到/etc/init.d/目录下

使用mv命令将脚本process_manager.sh移动到/etc/init.d目录。该目录一般用来存放服务类进程的脚本。请注意,命令中的#符号是操作系统的命令提示符,表示需要在root用户下运行命令。

     #mv process_manager.sh /etc/init.d/

注意:如果是Ubuntu系统,需要在命令前添加sudo,否则会提示权限不够。

     $sudo   mv process_manager.sh /etc/init.d/

3)为脚本增加可执行权限

     #cd  /etc/init.d
     #chmod +x process_manager.sh

使用chmod命令为脚本process_manager.sh添加可执行权限。

4)编写启动脚本

process_manager.sh需要start、stop作为参数才能使用,因此,编写startll.sh脚本用来调用process_manager.sh。startall.sh脚本内容如下。

     #! /bin/sh
     /etc/init.d/process_manager.sh start
     #cd  /etc/init.d
     #chmod +x startall.sh

然后,为startall.sh脚本添加可执行权限。

5)查看系统级别

运行runlevel查看系统运行级别,默认情况下为2。这里得到的结果是5,表示系统启动时自动加载/etc/rc5.d目录中的启动脚本。

     $runlevel
     N 5

6)进入对应的/etc/rcx.d/目录

使用runlevel得到的结果是5,因此需要进入/etc/rc5.d目录。

     #cd /etc/rc5.d/

7)为脚本创建软链接

使用ln命令创建软链接,使系统进入这一runlevel时,能自动运行脚本。ln命令格式如下。

     ln  -s  软链接指向的文件全路径  软链接文件名

ln命令的例子如下。S99startall为软链接的名字,其中99表示启动序号,取值范围0~99,启动序号越大表示启动顺序越靠后。如果进程需要访问数据库或者有其他依赖项,最好把启动序号调大。

     #ln -s /etc/init.d/startall.sh S99startall

8)验证进程能否随操作系统自动启动

用reboot命令重启系统,系统启动后,会自动通过软链接调用脚本/etc/init.d/startall.sh。系统自动调用时运行的命令其实是process_manager.sh start。系统启动后,可以使用ps命令查看程序是否已经自动运行。比如,查看系统中有没有包含ks02字样的进程,可以写成:

     ps -ef | grep  ks02

如果显示输出中有脚本中配置的进程,则自启动脚本配置成功,如图2-61所示。

2.启动单个进程的脚本

1)编写脚本startp.sh

其实,启动单个进程的脚本跟启动所有进程的脚本基本一致。区别在于对start、stop参数的处理。process_manager.sh需要处理所有进程,因此在start、stop分支中需要启动或退出所有进程。而startp.sh仅需要处理单个进程,所以只需要写这一个进程的处理代码即可。

2)部署脚本startp.sh

脚本startp.sh用来启动单个进程,一般在用户已经登录桌面的情况下使用。因此,把这个脚本放在/usr/local/bin中即可(要确保这个目录已经被添加到PATH环境变量)。该脚本使用方法为:startp.sh待启动的进程名。比如:startp.sh ks02_09_d。

本节的脚本process_manager.sh、startp.sh、startall.sh存放在script目录,该目录与src目录是同一级目录。