首頁 > 系統教程 > Linux > 主體

剖析Linux的守護神

PHPz
發布: 2024-04-29 12:28:13
轉載
518 人瀏覽過
後台程式與守護程式的差異
    最大的差異有以下幾點:
  • (a)守護程式已經完全脫離終端控制台了,而後台程式並未完全脫離終端(在終端機未關閉前還是會往終端輸出結果);
  • (b)守護程式在關閉終端控制台時不會受影響,而後台程式會隨使用者退出而停止,需要在以nohup command & 格式運作才能避免影響;
  • (c)守護程式的會話群組和目前目錄,檔案描述符都是獨立的。後台運行只是終端進行了一次fork,讓程式在後台執行,這些都沒改變;

剖析Linux的守護神

#守護程式的特性

#守護程式(Daemon)是在後台運行的一種特殊進程,它脫離於終端,從而這可避免進程被任何終端所產生的信號打斷,它在執行進程中的產生資訊也不在任何終端上顯示。守護程式週期性地執行某種任務或等待處理某些發生的事件,Linux的大多數伺服器就是用守護程式實現的。

守護程式程式設計要點
    1. #屏蔽一些有關控制終端操作的訊號,是為了防止在守護程序沒有正常啟動起來之前,控制終端受到干擾退出或掛起。程式碼如下:
      /* 处理可能的终端信号 */
      signal(SIGTTOU, SIG_IGN);
      signal(SIGTTIN, SIG_IGN);
      signal(SIGTSTP, SIG_IGN);
      signal(SIGHUP , SIG_IGN);
      
      登入後複製
    2. 在背景運行。
      /* 是父进程,结束父进程,子进程继续 */
      if(fork())
          exit(0);
      
      登入後複製
    3. 脫離控制終端和進程組:
      • (1)一個進程屬於一個進程組,進程組號(PGID)就是進程組長的進程號(PID)
      • (2)同進程組中的進程共享一個控制終端,這個控制終端預設是創建進程的終端
      • (3)一個進程關聯的控制終端和進程組通常是從父進程繼承下來的,因此,這個子進程仍然受到父親進程終端的影響,因為終端產生的訊號會發送給前台進程組的所有進程。

      基於上述原因,需要讓為個子進程徹底擺脫該終端的影響,需要呼叫setsid()使子進程成為新的會話組長,程式碼如下:

      setsid();
      登入後複製

      setsid()呼叫成功後,呼叫此函數的程序成為新的會話組長和新的程序組長,並與原來的程序組脫離關係。由於會話過程對控制終端的獨佔性,進程同時與控制終端脫離。

    4. 禁止進程重新開啟控制終端,採用的辦法是再次建立一個子進程,並讓父親進程退出,該子進程不再是會話群組長,從而達到目的。程式碼如下:
      /* 结束第一子进程,第二子进程继续 */
      if(fork())
          exit(0);
      
      登入後複製
    5. 關閉開啟的檔案描述符。因為進程從創建它的父進程繼承了打開的檔案描述符,一般情況下不再需要。如不關閉,將會浪費系統資源。程式碼如下:
      #define NOFILE  256
      
      for(i=0; i
      登入後複製

       

    6. 改變目前工作目錄。進程活動時,其工作目錄所在的檔案系統不能卸載。因此需要將守護程式的工作目錄改變到適當的目錄。程式碼如下:
      chdir("/tmp");
      登入後複製
    7. 重設檔案建立遮罩。進程從創建它的父進程繼承了檔案創建掩碼。它可能修改守護程式所建立的檔案的存取權限。程式碼如下:
      umask(0);
      
      登入後複製
    8. 處理SIGCHLD訊號(子進程退出訊號)。如果不等待子程序結束,子程序將成為殭屍程序從而佔用系統內核資源。
      /* 将子进程退出信号设为SIG_IGN,让系统帮助回收进程资源 */
      signal(SIGCHLD, SIG_IGN);
      登入後複製

      整體程式碼如下:

      #define NOFILE      256
      
      void DaemonMode()
      {
          int num = 0;
          int fd0, fd1, fd2;
      
          /* 屏蔽可能的信号 */
          signal(SIGTTOU, SIG_IGN);
          signal(SIGTTIN, SIG_IGN);
          signal(SIGTSTP, SIG_IGN);
          signal(SIGHUP , SIG_IGN);
      
          if(fork())
              exit(0);
      
          setsid();
      
          if(fork())
              exit(0);
      
          chdir("/tmp/httpd");
      
          umask(0);
      
          for(; num
      登入後複製

       

補充 setsid() 函數函數:

如果呼叫進程已經是一個進程組的組長,則此函數會傳回錯誤。為了杜絕這種情況,通常先呼叫fork()來建立子進程,然後使其父進程終止,而子進程繼續,在子進程中呼叫此函數。

如果呼叫此函數的進程不是一個進程組組長,則此函數會建立一個新會話,調用setsid()函數的進程成為新的會話的領頭進程,並與其父進程的會話組和進程組脫離。由於會話對控制終端的獨佔性,進程同時與控制終端脫離。

以上是剖析Linux的守護神的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:linuxprobe.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!