天天看點

建立守護程序步驟與setsid() -- linux deamon程序

一,守護程序概述

Linux Daemon(守護程序)是運作在背景的一種特殊程序。它獨立于控制終端并且周期性地執行某種任務或等待處理某些發生的事件。它不需要使用者輸入就能運作而且提供某種服務,不是對整個系統就是對某個使用者程式提供服務。Linux系統的大多數伺服器就是通過守護程序實作的。常見的守護程序包括系統日志程序syslogd、 web伺服器httpd、郵件伺服器sendmail和資料庫伺服器mysqld等。

守護程序一般在系統啟動時開始運作,除非強行終止,否則直到系統關機都保持運作。守護程序經常以超級使用者(root)權限運作,因為它們要使用特殊的端口(1-1024)或通路某些特殊的資源。

一個守護程序的父程序是init程序,因為它真正的父程序在fork出子程序後就先于子程序exit退出了,是以它是一個由init繼承的孤兒程序。守護程序是非互動式程式,沒有控制終端,是以任何輸出,無論是向标準輸出裝置stdout還是标準出錯裝置stderr的輸出都需要特殊處理。

守護程序的名稱通常以d結尾,比如sshd、xinetd、crond等

二,建立守護程序步驟

首先我們要了解一些基本概念:

程序組 :

  • 每個程序也屬于一個程序組
  • 每個程序主都有一個程序組号,該号等于該程序組組長的PID号 .
  • 一個程序隻能為它自己或子程序設定程序組ID号

會話期:

會話期(session)是一個或多個程序組的集合。

setsid()函數可以建立一個對話期:

 如果,調用setsid的程序不是一個程序組的組長,此函數建立一個新的會話期。

(1)此程序變成該對話期的首程序

(2)此程序變成一個新程序組的組長程序。

(3)此程序沒有控制終端,如果在調用setsid前,該程序有控制終端,那麼與該終端的聯系被解除。 如果該程序是一個程序組的組長,此函數傳回錯誤。

(4)為了保證這一點,我們先調用fork()然後exit(),此時隻有子程序在運作

現在我們來給出建立守護程序所需步驟:

編寫守護程序的一般步驟步驟:

(1)在父程序中執行fork并exit推出;

(2)在子程序中調用setsid函數建立新的會話;

(3)在子程序中調用chdir函數,讓根目錄 ”/” 成為子程序的工作目錄;

(4)在子程序中調用umask函數,設定程序的umask為0;

(5)在子程序中關閉任何不需要的檔案描述符

說明:

1. 在背景運作。 

為避免挂起控制終端将Daemon放入背景執行。方法是在程序中調用fork使父程序終止,讓Daemon在子程序中背景執行。 

if(pid=fork()) 

exit(0);//是父程序,結束父程序,子程序繼續 

2. 脫離控制終端,登入會話和程序組 

有必要先介紹一下Linux中的程序與控制終端,登入會話和程序組之間的關系:程序屬于一個程序組,程序組号(GID)就是程序組長的程序号(PID)。登入會話可以包含多個程序組。這些程序組共享一個控制終端。這個控制終端通常是建立程序的登入終端。 

控制終端,登入會話和程序組通常是從父程序繼承下來的。我們的目的就是要擺脫它們,使之不受它們的影響。方法是在第1點的基礎上,調用setsid()使程序成為會話組長: 

setsid(); 

說明:當程序是會話組長時setsid()調用失敗。但第一點已經保證程序不是會話組長。setsid()調用成功後,程序成為新的會話組長和新的程序組長,并與原來的登入會話和程序組脫離。由于會話過程對控制終端的獨占性,程序同時與控制終端脫離。 

3. 禁止程序重新打開控制終端 

現在,程序已經成為無終端的會話組長。但它可以重新申請打開一個控制終端。可以通過使程序不再成為會話組長來禁止程序重新打開控制終端: 

exit(0);//結束第一子程序,第二子程序繼續(第二子程序不再是會話組長) 

4. 關閉打開的檔案描述符 

程序從建立它的父程序那裡繼承了打開的檔案描述符。如不關閉,将會浪費系統資源,造成程序所在的檔案系統無法卸下以及引起無法預料的錯誤。按如下方法關閉它們: 

for(i=0;i 關閉打開的檔案描述符close(i);> 

5. 改變目前工作目錄 

程序活動時,其工作目錄所在的檔案系統不能卸下。一般需要将工作目錄改變到根目錄。對于需要轉儲核心,寫運作日志的程序将工作目錄改變到特定目錄如/tmpchdir("/") 

6. 重設檔案建立掩模 

程序從建立它的父程序那裡繼承了檔案建立掩模。它可能修改守護程序所建立的檔案的存取位。為防止這一點,将檔案建立掩模清除:umask(0); 

7. 處理SIGCHLD信号 

處理SIGCHLD信号并不是必須的。但對于某些程序,特别是伺服器程序往往在請求到來時生成子程序處理請求。如果父程序不等待子程序結束,子程序将成為僵屍程序(zombie)進而占用系統資源。如果父程序等待子程序結束,将增加父程序的負擔,影響伺服器程序的并發性能。在Linux下可以簡單地将SIGCHLD信号的操作設為SIG_IGN。 

signal(SIGCHLD,SIG_IGN); 

這樣,核心在子程序結束時不會産生僵屍程序。這一點與BSD4不同,BSD4下必須顯式等待子程序結束才能釋放僵屍程序。

if (fork() != 0) {
    exit(0);
  }
  setsid();
  if (fork() != 0) {
    exit(0);
  }

  close(0);
  close(1);
  close(2);
  open("/dev/null", O_RDWR);
  dup(0);
  dup(0);
  return true;
}