本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
系列文章導航:《Unix 網路程式設計》筆記
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
守護行程的特點:
守護行程的啟動
由系統初始化指令碼啟動,通常位於 /etc/rc
或 /etc
目錄下,由這些指令碼啟動的守護行程一開始就有用超級使用者特權
如:inetd 超級伺服器、Web 伺服器、sendmail 伺服器
由 inetd 超級伺服器啟動,它監聽網路請求
cron 守護行程按照規則定期執行一些程式,由它執行的程式同樣作為守護行程執行
at 命令用於在未來某個時刻執行一些程式
守護行程還可以從使用者終端或在前臺或者後臺啟動,這麼做往往是為了測試
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
由於這段程式碼涉及的知識點比較多,所以首先需要補充一點作業系統的知識:Linux 程序、行程群組、對談週期、控制終端
按照上文中的描述閱讀下述程式碼:
- 在父程序(此時是一個行程群組的組長)中使用fork()產生子程序(將來的守護行程由它產生)
- 呼叫setsid(),用於生成一個新的對談 注意如果當前程序是對談組長時,呼叫失敗。第一點已經可以保證程序不是對談組長了,所以setsid()呼叫成功後,程序成為新的對談組長和新的行程群組長,並與原來的登入對談和行程群組脫離。由於對談對控制終端的獨佔性,程序同時與控制終端脫離
- 禁止程序重新開啟控制終端 第二步之後,程序已經成為無終端的對談組長。但它可以重新申請開啟一個控制終端。可以通過使程序不再成為對談組長來禁止程序重新開啟控制終端,在上面的控制終端中已經提到了只有對談組長才能開啟控制終端;
#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
訊號,許多守護行程因此把這個訊號作為來自系統管理員的一個通知,表示其組態檔已發生改動,守護行程應該重新讀取其組態檔。同理還有 SIGINT
和 SIGWINCH
等等
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://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);
}
}
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
Unix 系統中的 syslogd 守護行程通常由某個系統初始化指令碼啟動,並且在系統工作期間一直執行
啟動的步驟:
/etc/syslog.conf
,設定了對訊息的處理/var/run/log
(或 /dev/log
)SIGHUP
訊號,則重新讀取組態檔 (這讓我想到了 NGINX 過載組態檔時服務無需暫停)較新的 syslogd 實現禁止建立 UDP 通訊端,因為這樣可能會讓系統遭到 DOS 攻擊,其檔案系統可能被填滿,從而佔滿記憶體空間,或擠掉合法的紀錄檔訊息
我們一般不會直接向其傳送訊息,而是通過 syslog 函數寫入紀錄檔!
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
守護行程記錄訊息可以使用 syslog 函數:
#include <syslog.h>
void syslog(int priority, // 優先順序
const char *message, // 訊息
...)
引數解釋:
%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 的尾部
一些細節
/var/run/log
)這個通訊端一直保持開啟,直到程序終止openlog
和 closelog
來操作上述步驟,在首次呼叫 syslog 前呼叫 openlog,不需要傳送紀錄檔時呼叫 closelogopenlog 和 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 |
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
原來的系統服務模型
Unix 上的很多服務,如 SSH、FTP、Telnet 等,我們都可以把它當作一個 Server 端
在系統啟動的過程中,這些程序從 /etc/rc
檔案中啟動,而且每個程序都執行幾乎相同的啟動任務:
這種方式的缺點
inted 守護行程
為了解決這種問題,4.3BSD 提供一個因特網超級伺服器(即 inetd 守護行程):
daemon_init
函數的必要本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://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 指定的命令列引數 |
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
其工作流程如下:
讀入組態檔,為每個服務建立一個合適的通訊端
為每個通訊端呼叫 bind,指定埠和通配地址
埠號可以通過 getservbyname 獲取,用組態檔中的 service-name 和 protocal 欄位做引數
對於每個 TCP 通訊端,呼叫 listen 以接受外來的連線請求,對於 UDP 則不執行
建立完所有通訊端後,呼叫 select 等待其中任何一個通訊端變得可讀
對於 TCP:
如果設定為 wait,對於 TCP 來說,父程序會用 FD_CLR
禁止這個通訊端,儲存子程序 ID,當子程序終止(SIGCHILD
)後才繼續監聽
對於 UDP:
因為資料包伺服器只有一個通訊端,所以只能一個一個來處理,也就是說通過接受子程序終止的 SIGCHLD
訊號後才繼續監聽
因為假如 fork 後一個子程序,而父程序先於該子程序再次執行,則會由於還沒讀取資料而再次觸發 select 的事件,從而再次 fork 一個無用的子程序
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://www.cnblogs.com/lymtics/p/16341341.html |
xinetd 提供與 inetd 一致的基本服務,不過還提供了數目眾多的其他特性,包括根據客戶的地址登記、接受或拒絕連線的選項等等
本文資訊 | 本文資訊 | 防爬蟲替換資訊 |
---|---|---|
作者網站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
聯絡方式 | [email protected] | [email protected] |
原文標題 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 | 《Unix 網路程式設計》13:守護行程和 inet 超級伺服器 |
原文地址 | https://www.cnblogs.com/lymtics/p/16341341.html | https://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);
}
為了啟動這個程式,我們需要在 /etc/services
檔案中新增:
mydaytime 9999/tcp
在 /etc/inetd.conf
中新增:(在題主的電腦裡就只有 xinetd.conf 了)
mydaytime stream tcp nowait andy /foo/bar/daytimetcpsrv3 daytimetcpsrv3
然後給 inetd 傳送一個 SIGHUP 訊號,告知它重新讀取組態檔