Linux下編寫腳本實現Daemon

Linux(以Redhat Linux Enterprise Edition 5.3爲例)下,有時需要編寫ServiceService也是程序,一般隨系統啓動用戶不干預就不退出的程序,可以稱爲ServiceLinux下的Service一般稱爲Daemon

 

以上是廣義的Service的定義。Linux下的服務一般放在/etc/init.d文件夾下。瀏覽一下這個文件夾下的文件,可以發現在Linux下編寫Service一般遵循的原則。

 

Linux下編寫Service一般遵循的原則

1)真正運行的Service一般放在某個bin目錄下(/bin/usr/binetc)。

2/etc/init.d文件夾下一般是shell腳本,用來控制bin目錄下的Service

3/etc/init.d文件夾下的shell腳本一般接受至少兩個參數,startstop。還有其他常用的可選參數如statusreloadrestart,等。

4/etc/init.d文件夾下的shell腳本至少包括兩行註釋,一行告訴chkconfig此服務運行的runlevel,啓動優先級,結束優先級。一行告訴chkconfig此服務的描述。

 

Linux的啓動過程和RunLevel

要理解Linux的啓動過程和RunLevel,可以先瀏覽一下/etc/inittab文件。在/etc/inittab中定義了下面7RunLevel。每個Service可以設置自己在哪個RunLevel下運行。可以調用/sbin/init <runlevel>進入相應的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。如下,代表缺省RunLevel5

 

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 <runlevel>rc腳本會到相應的rcN.d中去執行下面的腳本。rc.local是最後調用的腳本,可以放一些用戶自定義的任務在裏面。

 

進入rcN.d文件夾下,會發現以SK開頭的腳本的鏈接,SK後面還帶2位數字。其中S代表StartK代表KillS開頭的腳本,在rc中調用的時候會帶start參數;K開頭的腳本,在rc中調用的時候會帶stop參數。SK後面帶的2位數字代表Service的優先級,數字越大,越後執行。這些腳本的鏈接的目的地多半都在/etc/init.d文件夾下。

 

現在一切都清晰了。我們可以通過在相應的rcN.d文件夾下按既定的規範創建/etc/init.d下腳本的軟鏈接的方式來控制系統啓動和退出時服務的啓動和結束。但是用手動的方式創建軟鏈接來管理畢竟不方便,RedHatLinux提供了chkconfig來幫助創建這些軟鏈接。只要放在/etc/init.d下的服務控制腳本符合前面提到的chkconfig的約定(註釋chkconfig  description),就可以用chkconfig --add <service> chkconfig --list <service> chkconfig --del <service>等命令來控制service的啓動與否。

 

一個例子

下面是用c++語言寫的一個Service,此Service/tmp/random文件中,每隔5秒生成一個4位隨機數字。通過g++ -o myrand myrand.cpp編譯。然後把myrand放到/root/bin/文件夾下。


myrand.cpp

/* myrand.cpp
 * this program read 4 chars from /dev/random in each iteration,
 * and then adjust it to 0-9. Finally the 4 chars are written
 * to /tmp/random. This is only for testing /dev/random, and
 * at the same time serve as a example service.
 */
#include <iostream>
#include <fstream>
using namespace std;
#include <unistd.h>
 
 
int main()
{
                while (true)
                {
                                ifstream ifile("/dev/random");
                                char ch;
                                char str[5];
                                str[4]=0;
                                int i;
                                for(i=0;i<4;i++)
                                {
                                                ifile >> ch;
                                                if(ch<0) ch=-ch;
                                                ch = ch % 10;
                                                ch='0' + ch;
                                                str[i]=ch;
                                }
 
                                ofstream ofile("/tmp/random");
                                ofile << str << endl;
                                sleep(5);
                }
}

下面是一個腳本,名字是myrandservice,放在/etc/init.d文件夾下:


#!/bin/sh
#
# chkconfig: 2345  80 50
# description: myrandservice is for testing how to write service in Linux
#             
# processname: myrandservice
#
# Source function library.
. /etc/rc.d/init.d/functions
 
 
ret=0
 
 
start() {
    # check fdb status
                echo "start myrandservice"
                daemon /root/bin/myrand &
                ret=$?
}
 
stop() {
    echo "stop myrandservice"
                kill -9 $(ps -ef | grep myrand | grep -v grep | awk '{print $2}')
                ret=$?
}
 
status() {
                local result
                echo "check status of myrandservice..."
                #lines=$( ps -ef | grep myrand | grep -v grep  |  )
                #echo $lines
                result=$( ps -ef | grep myrand | grep -v myrandservice | grep -v grep | wc -l )
                #echo $result
                if [ $result -gt 0 ] ; then
                                echo "my randservice is up"
                                ret=0
                else
                                echo "my randservice is down"
                                ret=1
                fi
                echo "check status of myrandservice...done."
}
 
# See how we were called.
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
                                status
        ;;
  *)
        echo {1}quot;Usage: $0 {start|stop|status}"
        exit 1
esac
 
exit $ret

例子的一些說明

例子中腳本的下面兩行既是給chkconfig用的。其中2345代表此服務在RunLevel 2, 3, 4, 5下開啓;80代表啓動優先級;50代表結束優先級。如果RunLevel處不添值,用“-”代替,則代表此服務在任何runlevel下都不會自動啓動,需要手動啓動。可以通過service <service-name> start/stop/status等來控制或查詢Service

 

# chkconfig: 2345  80 50

# description: myrandservice is for testing how to write service in Linux

 

腳本中的daemon函數存在於/etc/rc.d/init.d/functions中。daemon會重定向輸出到/dev/null,也會設置是否生成coredump文件。通過daemon啓動的程序,即使用戶退出了命令行shell,也會保證Service會運行而不會退出。在/etc/rc.d/init.d/functions中還包括其他一些有用的函數,如killprocstatus等,分別用來殺掉服務和查看服務狀態。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章