前言
在上篇中,我們已經發現了原來的併發回射程式隱藏的問題 - 殭屍子程式。
而在本篇中,我們將通過Linux的訊號機制,將這些不該存於世間的“ 殭屍 ”通通清理掉。
清理思路
在Linux中,每當子程式被撤銷,它都會傳送一個SIGCHLD訊號給核心。我們只需要設定相應機制捕獲這個訊號然後命令系統徹底清理掉原來的子程式即可。
第一步:定義註冊函式
函式作用:關聯訊號和訊號處理函式。
函式定義:
1 #include "unp.h" 2 3 Sigfunc * 4 signal(int signo, Sigfunc *func) 5 { 6 struct sigaction act, oact; 7 8 // 記錄訊號處理函式 9 act.sa_handler = func; 10 // 設定額外阻塞訊號 11 sigemptyset(&act.sa_mask); 12 // 設定訊號處理的其他相關操作 13 act.sa_flags = 0; 14 15 if (signo == SIGALRM) { 16 #ifdef SA_INTERRUPT 17 // 設定被訊號所中斷的系統呼叫不自動重啟 18 act.sa_flags |= SA_INTERRUPT; 19 #endif 20 } else { 21 #ifdef SA_RESTART 22 // 設定被訊號所中斷的系統呼叫自動重啟 23 act.sa_flags |= SA_RESTART; 24 #endif 25 } 26 // 正是註冊訊號及訊號的處理函式 27 if (sigaction(signo, &act, &oact) < 0) 28 return(SIG_ERR); 29 // 返回訊號處理函式指標 30 return(oact.sa_handler); 31 }
第二步:定義訊號處理函式
函式作用:接收到指定訊號後撤銷殭屍子程式。
函式定義:
1 #include "unp.h" 2 3 void 4 sig_chld(int signo) 5 { 6 pid_t pid; 7 int stat; 8 9 // waitpid 函式中,-1表示即將終止的子程式,stat返回子程式的終止狀態,WNOHANG引數告知核心在沒有已終止核心時不要阻塞。 10 while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) 11 printf("child %d terminated\n", pid); 12 return; 13 }
注:waitpid包含於標頭檔案 sys/wait.h
第三步:修改伺服器程式碼並啟用清理機制
=>我們需要新增以下幾個部分程式碼:
1. 呼叫註冊函式
2. 為了便於移植,對一些慢中斷函式手工自動重啟。
=>執行測試:
1. 在一個終端以超級使用者許可權啟動伺服器
2. 在另幾個終端開啟客戶端並輸入IP地址引數127.0.0.1
3. 執行回射測試,每當有客戶結束終端時,顯示情況如下:
表示這些子程式都被真的“ 殺死 ”了。再檢視當前程式狀態驗證之:
哦也,果然沒有殭屍程式了。