在Linux下编写Daemon
在Linux(以Redhat Linux Enterprise Edition 5.3為例)下,有時需要編寫Service。Service也是程序,一般隨系統啟動用戶不干預就不退出的程序,可以稱為Service。Linux下的Service一般稱為Daemon。
以上是廣義的Service的定義。Linux下的Service一般放在/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>進入相應的RunLevel,比如運行/sbin/init 6就會導致系統重啟。如果在某個RunLevel下某個服務不能啟動,導致系統啟動失敗,可以進入沒有配置此服務的RunLevel來禁用或修改此服務(有點類似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文件夾下,執行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文件夾下,會發現以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 <service> chkconfig --list <service> chkconfig --del <service>等命令來控制service的啟動與否。
三 一個例子
1)下面是用c++語言寫的一個Service,此Service在/tmp/random文件中,每隔5秒生成一個4位隨機數字。通過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設置為自動啟動。 同時可以在rc3.d,rc4.d,rc5.d下面看到相應的腳本鏈接被自動地創建了。
4)例子的一些說明
例子中腳本的下面兩行既是給chkconfig用的。其中2345代表此服務在RunLevel 2, 3, 4, 5下開啟;80代表啟動優先級;50代表結束優先級。如果RunLevel處不添值,用“-”代替,則代表此服務在任何runlevel下都不會自動啟動,需要手動啟動。可以通過service <service-name> start/stop/status等來控制或查詢Service。
#chkconfig:23458050
#description:myrandserviceisfortestinghowtowriteserviceinLinux
腳本中的daemon函數存在于/etc/rc.d/init.d/functions中。daemon會重定向輸出到/dev/null,也會設置是否生成coredump文件。通過daemon啟動的程序,即使用戶退出了命令行shell,也會保證Service會運行而不會退出。在/etc/rc.d/init.d/functions中還包括其他一些有用的函數,如killproc,status等,分別用來殺掉服務和查看服務狀態。
四 deamon的另一種實現
不使用/etc/rc.d/init.d/functions中的daemon,則Daemon程序設計要遵從以下過程:
(1)程序運行后調用fork,并讓父進程退出。子進程獲得一個新的進程ID,但繼承了父進程的進程組ID。
(2)調用setsid創建一個新的session,使自己成為新session和新進程組的leader,并使進程沒有控制終端(tty)。
(3)設置文件創建mask為0,避免創建文件時權限的影響。
(4)關閉不需要的打開文件描述符。因為Daemon程序在后臺執行,不需要于終端交互,通常就關閉STDIN、STDOUT和STDERR。其它根據實際情況處理。
(5)Daemon無法輸出信息,可以使用SYSLOG或自己的日志系統進行日志處理。(可選)
(6)編寫管理Daemon的SHELL腳本,使用service對Daemon進行管理和監控。(可選)
參考:
http://www.cnblogs.com/khler/archive/2011/01/30/1947971.html
總結
以上是生活随笔為你收集整理的在Linux下编写Daemon的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python unpack infini
- 下一篇: oracle离线文档查dbms_Orac