以上是广义的Service的定义。Linux下的服务一般放在/etc/init.d文件夹下。浏览一下这个文件夹下的文件,可以发现在Linux下编写Service一般遵循的原则。
Linux下编写Service一般遵循的原则
1)真正运行的Service一般放在某个bin目录下(/bin,/usr/bin,etc)。
2)/etc/init.d文件夹下一般是shell脚本,用来控制bin目录下的Service。
3)/etc/init.d文件夹下的shell脚本一般接受至少两个参数,start和stop。还有其他常用的可选参数如status,reload,restart,等。
4)/etc/init.d文件夹下的shell脚本至少包括两行注释,一行告诉chkconfig此服务运行的runlevel,启动优先级,结束优先级。一行告诉chkconfig此服务的描述。
Linux的启动过程和RunLevel
要理解Linux的启动过程和RunLevel,可以先浏览一下/etc/inittab文件。在/etc/inittab中定义了下面7种RunLevel。每个Service可以设置自己在哪个RunLevel下运行。可以调用/sbin/init 进入相应的RunLevel,比如运行/sbin/init 6就会导致系统重启。如果在某个RunLevel下某个服务不能启动,导致系统启动失败,可以进入没有配置此服务的RunLevel来禁用或修改此服务(有点类似Windows下的安全模式)。
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
/etc/inittab文件下还定义了缺省RunLevel。如下,代表缺省RunLevel是5。
id:5:initdefault:
在/etc文件夹下,执行ls -d rc*,会列出下面这些文件和目录:
rc rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d rc.d rc.local rc.sysinit
rc是一个脚本,在/etc/inittab中,会根据RunLevel执行rc 。rc脚本会到相应的rcN.d中去执行下面的脚本。rc.local是最后调用的脚本,可以放一些用户自定义的任务在里面。
进入rcN.d文件夹下,会发现以S和K开头的脚本的链接,S和K后面还带2位数字。其中S代表Start,K代表Kill。S开头的脚本,在rc中调用的时候会带start参数;K开头的脚本,在rc中调用的时候会带stop参数。S和K后面带的2位数字代表Service的优先级,数字越大,越后执行。这些脚本的链接的目的地多半都在/etc/init.d文件夹下。
现在一切都清晰了。我们可以通过在相应的rcN.d文件夹下按既定的规范创建/etc/init.d下脚本的软链接的方式来控制系统启动和退出时服务的启动和结束。但是用手动的方式创建软链接来管理毕竟不方便,RedHatLinux提供了chkconfig来帮助创建这些软链接。只要放在/etc/init.d下的服务控制脚本符合前面提到的chkconfig的约定(注释chkconfig 和 description),就可以用chkconfig --add chkconfig --list chkconfig --del 等命令来控制service的启动与否。
一个例子
每隔10s在/tmp/dameon.log中写入一句话,用C语言编写,然后把它放到/root/bin下面:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <sys/wait.h>
- #include <signal.h>
- #define MAXFILE 65535
- volatile sig_atomic_t _running = 1;
- void sigterm_handler(int arg);
- void main()
- {
- pid_t pc;
- int i, fd, len;
- char *buf = "this is a Daemon\n";
- len = strlen(buf);
- //the first step
- pc = fork();
- if(pc < 0)
- {
- printf("error fork\n");
- exit(1);//abnormal exit
- }
- else if(pc > 0)
- {
- exit(0);//normal exit of parent process
- }
- //the second step
- setsid();
- //the third step
- chdir("/");
- //the forth step
- umask(0);
- //the fiveth step
- for(i = 0; i < MAXFILE; i++)
- {
- close(i);
- }
- signal(SIGTERM, sigterm_handler);
- while(_running)
- {
- if((fd = open("/tmp/daemon.log", O_CREAT|O_WRONLY|O_APPEND, 0600)) < 0)
- {
- perror("open");
- exit(1);
- }
- write(fd, buf, len);
- close(fd);
- usleep(10*1000);//10ms
- }
- }
- void sigterm_handler(int arg)
- {
- _running = 0;
- }
下面是一个脚本,名字为myTestService,放在/etc/init.d/下面:
- #!/bin/sh
- # chkconfig: 2345 80 50
- # description: myTestService is for testing how to write service in Linux
- # processname: myTestService
- # Source function library.
- #. /etc/rc.d/init.d/functions
- ret=0
- start() {
- # check fdb status
- echo "start myTestService"
- #daemon /root/bin/myrand &
- ./test &
- ret=$?
- }
- stop() {
- echo "stop myTestService"
- kill -9 $(ps -ef | grep test | grep -v grep | awk '{print $2}')
- ret=$?
- }
- status() {
- local result
- echo "check status of myTestService..."
- #lines=$( ps -ef | grep test | grep -v grep | )
- #echo $lines
- result=$( ps -ef | grep test | grep -v myTestService | grep -v grep | wc -l )
- #echo $result
- if [ $result -gt 0 ] ; then
- echo "myTestService is up"
- ret=0
- else
- echo "myTestService is down"
- ret=1
- fi
- echo "check status of myTestService...done."
- }
- # See how we were called.
- case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- status)
- status
- ;;
- *)
- echo $"Usage: $0 {start|stop|status}"
- exit 1
- esac
- exit $ret