FreeBSD 使用手冊
前一頁 | 章 3. UNIX 基礎概念 | 下一頁

# 3.8. Daemon、信號及終止程序

當在執行文書編輯器時，您可以很容易地使用它，叫它讀取檔案或是什麼的。 可以這樣做是因為編輯器有提供這些功能， 還有就是編輯器依附在一個終端機 (Terminal) 之上。 有些程式並不是設計成一直在接收使用者的輸入的， 所以它們在一開始執行的時候就從終端機斷開了。 例如說， 網頁伺服器整天都在回應網頁方面的要求，它通常不需要您輸入任何東西。 另外，像是把信從一個站傳送到另一個站的程式，也是這種類型的應用程式。

我們把這種程式稱作 daemon。 Daemon (惡魔、守護神) 是希臘神話中的角色：祂們不屬於善良陣營或邪惡陣營，是守護的小精靈。 大致上來說祂們就是在替人類做一些有用的事情， 跟今天的網頁伺服器或是郵件伺服器很像。 這也就是為何 BSD 的吉祥物，長期以來都是一隻穿著帆布鞋拿著三叉耙的快樂小惡魔的原因。

通常來說 deamon 程式的名字後面都會加一個字母 “d”。 BIND 是 Berkeley Internet Name Domain 的縮寫 (但實際上執行的程式名稱是 `named`)、Apache 網頁伺服器的程式名稱是 `httpd`、印表機服務程式是 `lpd`，依此類推。 這是習慣用法，並沒有硬性規定，例如 Sendmail 主要的寄信 daemon 是叫做 `sendmail` 而不是 `maild`，跟您想像的不一樣。

有些時候會需要跟某個 daemon 程序溝通， 這些溝通是透過所謂的信號(signal)來傳遞給該 daemon 程序(或是其他執行中的程序)。 藉由送出信號，您可以和一個 daemon (或是任何一個正在跑的程序) 溝通。 信號有很多種——有些有特定的意義，有些則是會由應用程式來解讀。 應用程式的說明文件會告訴您該程式是如何解讀信號的。 您只能送信號給您擁有的程序，送 kill(1) 或 kill(2) 的信號給別人的程序是不被允許的。 不過 `root` 不受此限制，他可以送信號給任何人的程序。

FreeBSD 本身在某些情況也會送信號給應用程式。 假設有個應用程式寫得很爛，然後企圖要存取它不該碰的記憶體的時候，FreeBSD 會送一個 Segmentation Violation 信號 (`SIGSEGV`) 給這個程序。 又如果有一個應用程式用了 alarm(3) 的 system call 要求系統在過一段時間之後叫他一下，時間到了的時候鬧鐘的信號 (`SIGALRM`) 就會被送出了，其他的依此類推。

`SIGTERM` and `SIGKILL` 這兩個信號可以拿來終止程序。 用 `SIGTERM` 結束程序是比較有禮貌的方式，該程序會捕捉 (catch) 這個信號而了解到您想要把他關掉。 接著下來它會把它自已開的記錄檔通通關掉， 然後在關掉程序之前結束掉手邊的工作。 在某些情況下程序有可能會裝作沒看見 `SIGTERM`，假如它正在做一些不能中斷的工作的話。

`SIGKILL` 就沒有辦法被程序忽略了。 這是一個“我管你正在幹嘛，現在就給我停下來”的信號。 如果您送了 `SIGKILL` 信號給某個程序，FreeBSD 將會把它停掉[1]。

這些是其他您有可能會要用到的信號： `SIGHUP`，`SIGUSR1`，以及 `SIGUSR2`。 這些是通用的信號，當送出時不同的應用程式會有不同的反應。

假設您更動了您的網頁伺服器的設定檔—— 您想要叫網頁伺服器去重新讀取設定值。 您可以關閉後再重新啟動 `httpd`，但是這麼做會造成網頁伺服器暫停服務一段時間， 這樣子可能不太好。 大部份的 daemon 都寫成會去回應 `SIGHUP`。 當收到這個信號之後，它們會去重新讀取自已的設定檔。 因此您可以用送 `SIGHUP` 信號來取代關掉重開。 又因為沒有標準在規範如何回應這些信號，不同的 daemon 可能會有不同的行為，所以有疑問的話請先確認並翻閱 deamon 的說明文件。

信號是由 kill(1) 指令送出的，如範例所示：

送信號給程序

這個範例將會示範如何送一個信號給 inetd(8)。 `inetd` 的設定檔是 `/etc/inetd.conf`，而 `inetd` 會在收到 `SIGHUP` 的時候重新讀取這個設定檔。

1. 找出您想要送信號的那個程序的 ID。 您會用到 ps(1) 以及 grep(1) 這兩個指令。 grep(1) 是用來在輸出中搜尋， 找出您指定的字串。 這個指令是由一般使用者執行，而 inetd(8) 是由 `root` 執行，所以在使用 ps(1) 時需要加上 `ax` 選項。

       % ps -ax | grep inetd
         198  ??  IWs    0:00.00 inetd -wW

   因此可知 inetd(8) 的 PID 為 198。 在某些情況下 `grep inetd` 這個指令本身也會出現在輸出裡。 這是因為 ps(1) 乃是找所有執行中的程序的方式造成的。

2. 用 kill(1) 來送信號。 又因為 inetd(8) 是由 `root` 執行的，您必須用 su(1) 切換成 `root`先。

       % su
       Password:
       # /bin/kill -s HUP 198

   一般情況對大多數 UNIX® 指令來講，當 kill(1) 執行成功時並不會輸出任何訊息。 假設您送一個信號給某個不是您所擁有的程序， 那麼您就會吃到這個錯誤訊息： “`kill: `PID`: Operation not permitted`”。 而如果您打錯 PID 的話，那就會把信號送給錯誤的程序。 這樣可能會很糟， 不過如果您夠幸運的話，可能剛好就只是把信號送給一個非使用中的 PID，那您就只會看到 “`kill: `PID`: No such process`” 而已。

   > 為什麼用 `/bin/kill`？: 很多 shell 有提供內建的 `kill` 指令。 也就是說這種 shell 會直接送信號，而不是執行 `/bin/kill`。 這樣是蠻方便的沒錯啦，但是不同的 shell 會有不同的語法來指定信號的名稱等。 與其嘗試去把它們通通學會，不如就單純的直接用 `/bin/kill `...`` 吧。

要送其他的信號的話也是非常類似，就視需要把指令中的 `TERM` 或 `KILL` 替換掉即可。

> 重要: 隨便抓一個系統中的程序然後把他砍掉並不是個好主意。 特別是 init(8)， process ID 1，一個非常特別的程序。 執行 `/bin/kill -s KILL 1` 的結果就是系統立刻關機。 因此在您按下 Return 要執行 kill(1)之前， 請一定要記得再次確認您下的參數。

### 注

[1] | 不完全正確——還是有少數東西不能被中斷。 例如有個程序正在從網路上的別的電腦讀一個檔案， 而那部電腦因為某些理由連不到 (機器被關掉，或是網路爛掉了)， 那這個程序我們就說他是一個“不能中斷的”程序。 通常在經過兩分鐘左右之後這個程序會逾時。 當發生逾時的時候這個程序就會被結束掉了。

前一頁 | 內容 | 下一頁
程序 | 上一層 | Shells

本文及其他文件，可由此下載：ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/。

若有 FreeBSD 方面疑問，請先閱讀 FreeBSD 相關文件，如不能解決的話，再洽詢 <questions@FreeBSD.org>。
關於本文件的問題，請洽詢 <doc@FreeBSD.org>。