在Linux下编写Daemon
在Linux(以Redhat Linux Enterprise Edition 5.3為例)下,有時需要編寫Service。Service也是程序,一般隨系統(tǒng)啟動用戶不干預就不退出的程序,可以稱為Service。Linux下的Service一般稱為Daemon。
以上是廣義的Service的定義。Linux下的Service一般放在/etc/init.d文件夾下。瀏覽一下這個文件夾下的文件,可以發(fā)現(xiàn)在Linux下編寫Service一般遵循的原則。
一 Linux下編寫Service一般遵循的原則
1)真正運行的Service一般放在某個bin目錄下(/bin,/usr/bin,etc)。
2)/etc/init.d文件夾下一般是shell腳本,用來控制bin目錄下的Service。
3)/etc/init.d文件夾下的shell腳本一般接受至少兩個參數(shù),start和stop。還有其他常用的可選參數(shù)如status,reload,restart,等。
4)/etc/init.d文件夾下的shell腳本至少包括兩行注釋,一行告訴chkconfig此服務(wù)運行的runlevel,啟動優(yōu)先級,結(jié)束優(yōu)先級。一行告訴chkconfig此服務(wù)的描述。
二 Linux的啟動過程和RunLevel
要理解Linux的啟動過程和RunLevel,可以先瀏覽一下/etc/inittab文件。在/etc/inittab中定義了下面7種RunLevel。每個Service可以設(shè)置自己在哪個RunLevel下運行??梢哉{(diào)用/sbin/init <runlevel>進入相應(yīng)的RunLevel,比如運行/sbin/init 6就會導致系統(tǒng)重啟。如果在某個RunLevel下某個服務(wù)不能啟動,導致系統(tǒng)啟動失敗,可以進入沒有配置此服務(wù)的RunLevel來禁用或修改此服務(wù)(有點類似Windows下的安全模式)。
#0-halt(DoNOTsetinitdefaulttothis)
#1-Singleusermode
#2-Multiuser,withoutNFS(Thesameas3,ifyoudonothavenetworking)
#3-Fullmultiusermode
#4-unused
#5-X11
#6-reboot(DoNOTsetinitdefaulttothis)
/etc/inittab文件下還定義了缺省RunLevel。如下,代表缺省RunLevel是5。
id:5:initdefault:
在/etc文件夾下,執(zhí)行l(wèi)s -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中,會根據(jù)RunLevel執(zhí)行rc <runlevel>。rc腳本會到相應(yīng)的rcN.d中去執(zhí)行下面的腳本。rc.local是最后調(diào)用的腳本,可以放一些用戶自定義的任務(wù)在里面。
進入rcN.d文件夾下,會發(fā)現(xiàn)以S和K開頭的腳本的鏈接,S和K后面還帶2位數(shù)字。其中S代表Start,K代表Kill。S開頭的腳本,在rc中調(diào)用的時候會帶start參數(shù);K開頭的腳本,在rc中調(diào)用的時候會帶stop參數(shù)。S和K后面帶的2位數(shù)字代表Service的優(yōu)先級,數(shù)字越大,越后執(zhí)行。這些腳本的鏈接的目的地多半都在/etc/init.d文件夾下。
現(xiàn)在一切都清晰了。我們可以通過在相應(yīng)的rcN.d文件夾下按既定的規(guī)范創(chuàng)建/etc/init.d下腳本的軟鏈接的方式來控制系統(tǒng)啟動和退出時服務(wù)的啟動和結(jié)束。但是用手動的方式創(chuàng)建軟鏈接來管理畢竟不方便,RedHatLinux提供了chkconfig來幫助創(chuàng)建這些軟鏈接。只要放在/etc/init.d下的服務(wù)控制腳本符合前面提到的chkconfig的約定(注釋chkconfig 和 description),就可以用chkconfig --add <service> chkconfig --list <service> chkconfig --del <service>等命令來控制service的啟動與否。
三 一個例子
1)下面是用c++語言寫的一個Service,此Service在/tmp/random文件中,每隔5秒生成一個4位隨機數(shù)字。通過g++ -o myrand myrand.cpp編譯。然后把myrand放到/root/bin/文件夾下。
/*myrand.cpp
*thisprogramread4charsfrom/dev/randomineachiteration,
*andthenadjustitto0-9.Finallythe4charsarewritten
*to/tmp/random.Thisisonlyfortesting/dev/random,and
*atthesametimeserveasaexampleservice.
*/
#include<iostream>
#include<fstream>
usingnamespacestd;
#include<unistd.h>
intmain()
{
while(true)
{
ifstreamifile("/dev/random");
charch;
charstr[5];
str[4]=0;
inti;
for(i=0;i<4;i++)
{
ifile>>ch;
if(ch<0)ch=-ch;
ch=ch%10;
ch='0'+ch;
str[i]=ch;
}
ofstreamofile("/tmp/random");
ofile<<str<<endl;
sleep(5);
}
}
2) 下面是一個腳本,名字是myrandservice,放在/etc/init.d文件夾下:
#!/bin/sh
#
#chkconfig:23458050
#description:myrandserviceisfortestinghowtowriteserviceinLinux
#
#processname:myrandservice
#
#Sourcefunctionlibrary.
./etc/rc.d/init.d/functions
ret=0
start(){
#checkfdbstatus
echo"startmyrandservice"
daemon/root/bin/myrand&
ret=$?
}
stop(){
echo"stopmyrandservice"
kill-9$(ps-ef|grepmyrand|grep-vgrep|awk'{print$2}')
ret=$?
}
status(){
localresult
echo"checkstatusofmyrandservice..."
#lines=$(ps-ef|grepmyrand|grep-vgrep|)
#echo$lines
result=$(ps-ef|grepmyrand|grep-vmyrandservice|grep-vgrep|wc-l)
#echo$result
if[$result-gt0];then
echo"myrandserviceisup"
ret=0
else
echo"myrandserviceisdown"
ret=1
fi
echo"checkstatusofmyrandservice...done."
}
#Seehowwewerecalled.
case"$1"in
start)
start
;;
stop)
stop
;;
status)
status
;;
*)
echo$"Usage:$0{start|stop|status}"
exit1
esac
exit$ret
3)使用/sbin/chkconfig --add myrandservice 來將次daemon設(shè)置為自動啟動。 同時可以在rc3.d,rc4.d,rc5.d下面看到相應(yīng)的腳本鏈接被自動地創(chuàng)建了。
4)例子的一些說明
例子中腳本的下面兩行既是給chkconfig用的。其中2345代表此服務(wù)在RunLevel 2, 3, 4, 5下開啟;80代表啟動優(yōu)先級;50代表結(jié)束優(yōu)先級。如果RunLevel處不添值,用“-”代替,則代表此服務(wù)在任何runlevel下都不會自動啟動,需要手動啟動??梢酝ㄟ^service <service-name> start/stop/status等來控制或查詢Service。
#chkconfig:23458050
#description:myrandserviceisfortestinghowtowriteserviceinLinux
腳本中的daemon函數(shù)存在于/etc/rc.d/init.d/functions中。daemon會重定向輸出到/dev/null,也會設(shè)置是否生成coredump文件。通過daemon啟動的程序,即使用戶退出了命令行shell,也會保證Service會運行而不會退出。在/etc/rc.d/init.d/functions中還包括其他一些有用的函數(shù),如killproc,status等,分別用來殺掉服務(wù)和查看服務(wù)狀態(tài)。
四 deamon的另一種實現(xiàn)
不使用/etc/rc.d/init.d/functions中的daemon,則Daemon程序設(shè)計要遵從以下過程:
(1)程序運行后調(diào)用fork,并讓父進程退出。子進程獲得一個新的進程ID,但繼承了父進程的進程組ID。
(2)調(diào)用setsid創(chuàng)建一個新的session,使自己成為新session和新進程組的leader,并使進程沒有控制終端(tty)。
(3)設(shè)置文件創(chuàng)建mask為0,避免創(chuàng)建文件時權(quán)限的影響。
(4)關(guān)閉不需要的打開文件描述符。因為Daemon程序在后臺執(zhí)行,不需要于終端交互,通常就關(guān)閉STDIN、STDOUT和STDERR。其它根據(jù)實際情況處理。
(5)Daemon無法輸出信息,可以使用SYSLOG或自己的日志系統(tǒng)進行日志處理。(可選)
(6)編寫管理Daemon的SHELL腳本,使用service對Daemon進行管理和監(jiān)控。(可選)
參考:
http://www.cnblogs.com/khler/archive/2011/01/30/1947971.html
總結(jié)
以上是生活随笔為你收集整理的在Linux下编写Daemon的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python unpack infini
- 下一篇: oracle离线文档查dbms_Orac