《Unix 網路程式設計》13:守護程式和 inetd 超級伺服器

樵仙發表於2022-06-04

守護程式和 inetd 超級伺服器

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

系列文章導航:《Unix 網路程式設計》筆記

守護程式

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

基本知識

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

守護程式的特點:

  • 必須親自脫離與控制終端的關聯,從而避免與作業控制、終端會話管理、終端產生訊號等發生任何不期望的互動
  • 同時要避免在後臺執行的守護程式非預期地輸出到終端

守護程式的啟動

  • 由系統初始化指令碼啟動,通常位於 /etc/rc/etc 目錄下,由這些指令碼啟動的守護程式一開始就有用超級使用者特權

    如:inetd 超級伺服器、Web 伺服器、sendmail 伺服器

  • 由 inetd 超級伺服器啟動,它監聽網路請求

  • cron 守護程式按照規則定期執行一些程式,由它執行的程式同樣作為守護程式執行

  • at 命令用於在未來某個時刻執行一些程式

  • 守護程式還可以從使用者終端或在前臺或者後臺啟動,這麼做往往是為了測試

daemon_init

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
  • 這是我們自己寫的一個函式,把一個普通程式轉變為守護程式
  • 部分 Unix 變體上提供一個名為 daemon 的 C 庫函式,實現類似的功能

由於這段程式碼涉及的知識點比較多,所以首先需要補充一點作業系統的知識:Linux 程式、程式組、會話週期、控制終端

按照上文中的描述閱讀下述程式碼:

  1. 在父程式(此時是一個程式組的組長)中使用fork()產生子程式(將來的守護程式由它產生)
  2. 呼叫setsid(),用於生成一個新的會話 注意如果當前程式是會話組長時,呼叫失敗。第一點已經可以保證程式不是會話組長了,所以setsid()呼叫成功後,程式成為新的會話組長和新的程式組長,並與原來的登入會話和程式組脫離。由於會話對控制終端的獨佔性,程式同時與控制終端脫離
  3. 禁止程式重新開啟控制終端 第二步之後,程式已經成為無終端的會話組長。但它可以重新申請開啟一個控制終端。可以通過使程式不再成為會話組長來禁止程式重新開啟控制終端,在上面的控制終端中已經提到了只有會話組長才能開啟控制終端;
#include <syslog.h>
#include "unp.h"

#define MAXFD 64

extern int daemon_proc; /* defined in error.c */

int daemon_init(const char* pname, int facility) {
    int i;
    pid_t pid;

    if ((pid = Fork()) < 0) // 失敗
        return (-1);
    else if (pid)   // 父程式
        _exit(0); /* parent terminates */

    /* child 1 continues... */

    // setsid 使得當前程式變為:
    // - 新會話的會話頭程式
    // - 新程式組的程式組頭程式
    if (setsid() < 0)
        return (-1);

    // 忽略 SIGHUP 訊號
    // 會話頭程式終止後,所有其他會話程式都會收到一個該訊號
    Signal(SIGHUP, SIG_IGN);
    if ((pid = Fork()) < 0)
        return (-1);
    else if (pid)
        _exit(0); /* child 1 terminates */

    /* child 2 continues... */

    // 告知錯誤處理函式使用 syslog 而不是 fprintf
    daemon_proc = 1; /* for err_XXX() functions */

  	// 改變工作目錄,否則就是在當前目錄下執行,可能產生破壞
    chdir("/");

    // 關閉前 64 個描述符,即使有些本身就沒有開啟
    for (i = 0; i < MAXFD; i++)
        close(i);

    /* redirect stdin, stdout, and stderr to /dev/null */
    // 這樣設定會佔用標準輸入、標準輸出和標準錯誤輸出的描述符
    // 防止在伺服器環境下,套接字佔用這些描述符,而後誤將系統資訊傳送給這些描述符
    open("/dev/null", O_RDONLY);
    open("/dev/null", O_RDWR);
    open("/dev/null", O_RDWR);

    openlog(pname, LOG_PID, facility);

    return (0); /* success */
}

守護程式在沒有控制終端的環境下執行,它絕對不會收到來自核心的 SIGHUP 訊號,許多守護程式因此把這個訊號作為來自系統管理員的一個通知,表示其配置檔案已發生改動,守護程式應該重新讀取其配置檔案。同理還有 SIGINTSIGWINCH 等等

改進時間伺服器

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
int main(int argc, char** argv) {
    int listenfd, connfd;
    socklen_t addrlen, len;
    struct sockaddr* cliaddr;
    char buff[MAXLINE];
    time_t ticks;

  	// 如果有一些顯而易見的錯誤,則立即丟擲,而不是在日誌中丟擲
    if (argc < 2 || argc > 3)
        err_quit("usage: daytimetcpsrv2 [ <host> ] <service or port>");

    // 使用我們的函式啟動
    daemon_init(argv[0], 0);

    if (argc == 2)
        listenfd = Tcp_listen(NULL, argv[1], &addrlen);
    else
        listenfd = Tcp_listen(argv[1], argv[2], &addrlen);

    cliaddr = Malloc(addrlen);

    for (;;) {
        len = addrlen;
        connfd = Accept(listenfd, cliaddr, &len);
        err_msg("connection from %s", Sock_ntop(cliaddr, len));

        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
        Write(connfd, buff, strlen(buff));

        Close(connfd);
    }
}

日誌訊息

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

syslogd

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

Unix 系統中的 syslogd 守護程式通常由某個系統初始化指令碼啟動,並且在系統工作期間一直執行

啟動的步驟:

  1. 讀取配置:通常為 /etc/syslog.conf ,配置了對訊息的處理
  2. 建立Unix域資料包套接字:給他繫結路徑名 /var/run/log (或 /dev/log
  3. 建立一個 UDP 套接字:繫結埠 514
  4. 開啟路徑名 /dev/klog:來自核心中的任何出錯訊息從這個“裝置”輸入
  5. 監聽:呼叫 select,監聽 2 ~ 4 步驟的描述符
    • 如果收到訊息,讀入並按照配置進行處理
    • 如果收到 SIGHUP 訊號,則重新讀取配置檔案 (這讓我想到了 NGINX 過載配置檔案時服務無需暫停)

較新的 syslogd 實現禁止建立 UDP 套接字,因為這樣可能會讓系統遭到 DOS 攻擊,其檔案系統可能被填滿,從而佔滿記憶體空間,或擠掉合法的日誌訊息

我們一般不會直接向其傳送訊息,而是通過 syslog 函式寫入日誌!

syslog

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

守護程式記錄訊息可以使用 syslog 函式:

#include <syslog.h>

void syslog(int priority, // 優先順序
           const char *message, // 訊息
           ...)

引數解釋:

  • priority:好理解,大多日誌都有日誌級別的功能
  • facility:用於標識傳送程式型別(函式的引數列表中沒有?因為這個要和 priority 用邏輯或使用)
  • message:訊息內容,類似 printf,不同的是其增加了 %m 規範,用以輸出當前 errno 值對應的錯誤資訊

案例

syslog(LOG_INFO|LOG_LOCAL2, "rename(%s, %s): %m", file1, fil)

/etc/syslog.conf

kern.* 				/dev/debug					# 核心的所有訊息傳送到控制檯
local7.debug 	/var/log/cisco.log	# 來自 local7 的所有訊息新增到檔案 cisco.log 的尾部

一些細節

  • 當 syslog 被應用程式首次呼叫時,它建立一個 Unix 域資料包套接字,然後呼叫 connect 連線到由 syslogd 守護程式建立的 Unix 域資料包套接字的眾所周知路徑名(如 /var/run/log )這個套接字一直保持開啟,直到程式終止
  • 可以用 openlogcloselog 來操作上述步驟,在首次呼叫 syslog 前呼叫 openlog,不需要傳送日誌時呼叫 closelog

openlog 和 closelog

#include <syslog.h>
void openlog(const char* ident, // 日誌的字首,通常是程式名
             int options, 			// 可選值
             int facility);			// 設定預設的列印設施的值
void closelog(void);
options 說明
LOG_CONS 若無法傳送到 syslogd 則登記到控制檯
LOG_NDELAY openlog 預設是懶漢載入,這個選項設定不延遲開啟,立刻建立套接字
LOG_PERROR 既傳送到 syslogd 守護程式,又登記到標準錯誤輸出
LOG_PID 隨每個日誌訊息等級程式 ID

inetd 守護程式

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

引入 inetd

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

原來的系統服務模型

Unix 上的很多服務,如 SSH、FTP、Telnet 等,我們都可以把它當作一個 Server 端

在系統啟動的過程中,這些程式從 /etc/rc 檔案中啟動,而且每個程式都執行幾乎相同的啟動任務:

  1. 建立一個套接字,繫結埠
  2. 等待連線或資料包的到來
  3. 派生子程式,子程式提供服務,父程式繼續監聽

這種方式的缺點

  1. 所有這些守護程式含有幾乎相同的啟動程式碼
  2. 每個守護程式在程式表中佔據一個表項,然而大多數時間他們處於睡眠狀態

inted 守護程式

為了解決這種問題,4.3BSD 提供一個因特網超級伺服器(即 inetd 守護程式):

  1. 通過由 inetd 處理普通守護程式的大部分啟動細節以簡化守護程式的編寫,這麼一來每個伺服器不再有呼叫 daemon_init 函式的必要
  2. 單個程式(inetd)就能為多個服務等待外來的客戶請求,以取代每個伺服器一個程式的做法

inetd 配置檔案

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

inetd 使用前文提到的方法把自己變成一個守護程式,然後讀取並處理自己的配置檔案,通常在 /etc/inetd.conf ,該檔案包括如下內容:

欄位 說明
service-name 必須在 /etc/services 檔案中定義
socket-type stream(TCP)、dgram(UDP)
protocol 必須在 /etc/protocols 檔案中定義:tcp或udp
wait-flag 對於 TCP 一般為 nowait,對於 UDP 一般為 wait
login-name 來自 /etc/passwd 的使用者名稱,一般為 root
server-program 呼叫 exec 指定的完整路徑名
server-program-arguments 呼叫 exec 指定的命令列引數

inetd 工作流程

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

其工作流程如下:

  1. 讀入配置檔案,為每個服務建立一個合適的套接字

  2. 為每個套接字呼叫 bind,指定埠和通配地址

    埠號可以通過 getservbyname 獲取,用配置檔案中的 service-name 和 protocal 欄位做引數

  3. 對於每個 TCP 套接字,呼叫 listen 以接受外來的連線請求,對於 UDP 則不執行

  4. 建立完所有套接字後,呼叫 select 等待其中任何一個套接字變得可讀

對於 TCP:

  1. 當 select 返回可讀後,如果該套接字是一個 TCP 套接字,而且其 wait-flag 為 nowait,則呼叫 accept 接受這個新連線
  2. inetd 守護程式呼叫 fork 派生程式,並由子程式處理服務請求,與前面的併發伺服器類似,關閉相應的描述符
  3. 子程式關閉除了要處理的套接字描述符外的所有的描述符,並根據配置檔案,切換到相應的使用者,用 exec 執行相應的操作

如果設定為 wait,對於 TCP 來說,父程式會用 FD_CLR 禁止這個套接字,儲存子程式 ID,當子程式終止(SIGCHILD)後才繼續監聽

對於 UDP:

因為資料包伺服器只有一個套接字,所以只能一個一個來處理,也就是說通過接受子程式終止的 SIGCHLD 訊號後才繼續監聽

因為假如 fork 後一個子程式,而父程式先於該子程式再次執行,則會由於還沒讀取資料而再次觸發 select 的事件,從而再次 fork 一個無用的子程式

xinetd

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

xinetd 提供與 inetd 一致的基本服務,不過還提供了數目眾多的其他特性,包括根據客戶的地址登記、接受或拒絕連線的選項等等

daemond_inetd

★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★
本文資訊本文資訊防爬蟲替換資訊
作者網站LYMTICShttps://lymtics.top
作者LYMTICS(樵仙)https://lymtics.top
聯絡方式me@tencent.mlme@tencent.ml
原文標題《Unix 網路程式設計》13:守護程式和 inet 超級伺服器《Unix 網路程式設計》13:守護程式和 inet 超級伺服器
原文地址https://www.cnblogs.com/lymtics/p/16341341.htmlhttps://www.cnblogs.com/lymtics/p/16341341.html
  • 如果您訪問本文的連結並非如上地址,則可能是爬取作者的文章,建議返回原站閱讀,謝謝您的支援
  • 原文會不斷地更新和完善排版和樣式會更加適合閱讀,並且有相關配圖
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★

這個函式的唯一作用就是為錯誤處理函式設定 daemon_proc 標誌,使得執行資訊輸出在日誌中

extern int daemon_proc; /* defined in error.c */

void daemon_inetd(const char* pname, int facility) {
    daemon_proc = 1; /* for our err_XXX() functions */
    openlog(pname, LOG_PID, facility);
}

修改後的伺服器程式碼:

int main(int argc, char** argv) {
    socklen_t len;
    struct sockaddr* cliaddr;
    char buff[MAXLINE];
    time_t ticks;

    daemon_inetd(argv[0], 0);

    cliaddr = Malloc(sizeof(struct sockaddr_storage));
    len = sizeof(struct sockaddr_storage);
    Getpeername(0, cliaddr, &len);
    err_msg("connection from %s", Sock_ntop(cliaddr, len));

    ticks = time(NULL);
    snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
    Write(0, buff, strlen(buff));

    Close(0); /* close TCP connection */
    exit(0);
}
  • 我們用描述符 0 指代被接受的 TCP 連線
  • 因為這個程式針對每一個連線啟動一次,所以不需要無限迴圈

為了啟動這個程式,我們需要在 /etc/services 檔案中新增:

mydaytime			9999/tcp

/etc/inetd.conf 中新增:(在題主的電腦裡就只有 xinetd.conf 了)

mydaytime stream tcp nowait andy /foo/bar/daytimetcpsrv3 daytimetcpsrv3

然後給 inetd 傳送一個 SIGHUP 訊號,告知它重新讀取配置檔案

相關文章