1. 程式人生 > >多程序併發如何防止殭屍程序——伺服器開發

多程序併發如何防止殭屍程序——伺服器開發

在併發伺服器設計中,很常用的一種辦法是用fork為每個連線建立子程序來單獨處理客戶端請求。

流程圖如下:


可見,在父程序中直接執行accept等待下一個連線而並沒有用wait或者waitpid來等待子程序返回。這會造成怎樣的後果呢?當子程序exit退出的時候,它並沒有真正銷燬,而是還著保留一個數據結構用來記錄它的退出狀態等資訊(因為父程序有可能會獲取該資訊)。若父程序不用wait或者waitpid等待,則此資訊會一直保留直到父程序退出。不幸的是,併發伺服器恰恰在正常情況會一直執行下去,並且不斷為每個連線創造子程序,久而久之造成嚴重的資源洩漏。所以併發伺服器必須採用某些手段來防止殭屍程序。

在子程序退出時會給父程序傳送一個SIGCHLD訊號,我們可以在父程序迴圈accept之前用signal來為SIGCHLD註冊一個回撥函式來等待子程序返回。

signal函式的宣告:

void (*signal(int signo,void (*func)(int)))(int);
這是一個含函式指標的函式宣告,它的第二個引數和返回值都是函式指標,也可以用以下宣告方式。
typedef void(*sig_t) ( int );
sig_t signal(int signo,sig_t func);

注:以上兩個函式宣告是同等的。

簡單來解釋:signal第一引數填的是要處理的訊號(這裡是SIGCHLD),第二個引數是收到這個訊號要呼叫的回撥函式的指標。

具體做法如下:

void sid_child(int signo)      //處理SIGCHLD訊號的回撥函式
{
    pid_t pid;
    int stat;
    while((pid=waitpid(-1,&stat,WNOHANG))>0);
    return;
}
//此處省略之前socket、bind
listen(servfd,10);
signal(SIGCHLD,sid_child);   //為SIGCHLD的註冊回撥函式sid_child
while(1)
{
      if((cliefd=accept(servfd,(sockaddr*)0,0))<0)
      {
          if(errno==EINTR) continue;
          else err_sys("accept call error");
      }
      //這裡省略fork建立子程序處理請求
}

解釋:

1、

signal(SIGCHLD,sid_child);  
呼叫後,當父程序收到有子程序傳來的SIGCHLD訊號,就會中斷呼叫回撥函式sid_child。

2、

while((pid=waitpid(-1,&stat,WNOHANG))>0);
在sid_child函式裡,迴圈呼叫waitpid等待子程序。

為什麼要迴圈呼叫waitpid? waitpid的用法是如何?

waitpid的宣告

pid_t waitpid(pid_t pid,int * status,int options);

這裡挑重點的講:waitpid功能是等待某個子程序返回,waitpid第一個引數是要等待返回的子程序ID號,若填-1則代表等待任意子程序返回。第二個引數用以接受子程序終止狀態。第三個是附加選項,,WNOHANG選項的意思使函式不阻塞,無論有沒子程序退出都返回。

WNOHANG選項下waitpid的呼叫特性:

2.1、當有子程序退出且正常返回時,返回子程序ID號;

2.2、當沒有子程序退出,返回0;

2.3、當調用出錯返回-1;

又因為無論有多少子程序只要有沒處理的子程序退出,就會父程序收到且只有一個SIGCHLD,所以while((pid=waitpid(-1,&stat,WNOHANG))>0); 的意思是:只有收到SIGCHLD訊號,就迴圈等待退出的子程序,直到waitpid返回非大於零的數(代表沒有子程序退出了)。之後又返回正常的迴圈中,accept等待連線。當下次有子程序退出,父程序會再一次收到SIGCHLD。

3、

 if((cliefd=accept(servfd,(sockaddr*)0,0))<0)
 {
       if(errno==EINTR) continue;
          else err_sys("accept call error");
 }
accept、write、read等都是慢系統呼叫。當伺服器阻塞在accept中時,我們知道父程序收到SIGCHLD就會發生中斷並呼叫我們註冊的回撥函式sid_child。當回撥函式返回時,慢系統呼叫的函式可能會返回一個EINTR錯誤,表明該函式在阻塞等待期間被中斷了。當然這個錯誤是我們設計預料之內的,所以我們得呼叫continue來繼續迴圈工作。

這樣就防止殭屍程序的出現。

相關推薦

程序併發如何防止殭屍程序——伺服器開發

在併發伺服器設計中,很常用的一種辦法是用fork為每個連線建立子程序來單獨處理客戶端請求。 流程圖如下: 可見,在父程序中直接執行accept等待下一個連線而並沒有用wait或者waitpid來等待子程序返回。這會造成怎樣的後果呢?當子程序exit退出的時候,它並沒有真正

Python程序併發操作中程序池Pool的應用

     在利用Python進行系統管理的時候,特別是同時操作多個檔案目錄,或者遠端控制多臺主機,並行操作可以節約 大量的時間。當被操作物件數目不大時,可以直接利用multiprocessing中的Process動態成生多個程序,10幾個 還好,但如果是上百個,上千個目標,

如何防止殭屍程序

1.殭屍程序:殭屍程序是當子程序比父程序先結束,而父程序又沒有回收子程序,釋放子程序佔用的資源,此時子程序將成為一個殭屍程序。如果父程序先退出 ,子程序被init接管,子程序退出後init會回收其佔用的相關資源。 2.產生原因: a. 子程序結束後向父程序發出SIGCHLD訊號,父程序預

編寫一unix程式,防止殭屍程序的出現.

殭屍程序的避免 ⒈父程序通過wait和waitpid等函式等待子程序結束,這會導致父程序掛起。 ⒉ 如果父程序很忙,那麼可以用signal函式為SIGCHLD安裝handler,因為子程序結束後

2.4 程序控制之殭屍程序和孤兒程序

學習目標:理解殭屍程序和孤兒程序形成的原因 一、孤兒程序 1. 孤兒程序: 父程序先於子程序結束,則子程序成為孤兒程序。子程序成為孤兒程序之後,init程序則會成為其新的父程序,稱為init程序領養孤兒程序。 2. 例程: 1 #include <stdio.h> 2 #incl

Linux程序併發伺服器(TCP)

Linux多程序併發伺服器(TCP) 前言:在Linux環境下多程序的應用很多,其中最主要的就是網路/客戶伺服器。多程序伺服器是當客戶有請求時 ,伺服器用一個子程序來處理客戶請求。父程序繼續等待其它客戶的請求。這種方法的優點是當客戶有請求時 ,伺服器能及時處理客戶 ,特別是在客戶伺服

Linux學習之網路程式設計(程序併發伺服器

言之者無罪,聞之者足以戒。 - “詩序” 上面我們所說過的通訊都是一個伺服器一個客戶端之間的通訊,下面我們來交流一下多程序併發伺服器的相關知識 邏輯上就是這個樣子的,就是一個伺服器多個客戶端進行資料的傳輸。 1、傳送資料的函式: ssize_t send(int sockfd,

linux網路程式設計之程序併發伺服器

1)使用多程序併發伺服器考慮的因素:       (1)父程序描述最大檔案描述符的個數(父程序需要關閉accept返回的新檔案描述符)       (2)系統內可建立程序的個數(與記憶體大小相關)       (3)程序建立過多是否降低整體服務效能 2)多程序建立併發

嵌入式linux-sqlite3資料庫,程序併發伺服器,線上詞典

文章目錄 1,簡介: 2,框架圖 2.1,客戶端框架 2.1,伺服器端框架 3,程式碼 3.1,客戶端程式碼 3.2,伺服器端程式碼 1,簡介: 1,線上詞典

嵌入式Linux網路程式設計,TCP併發伺服器,TCP執行緒併發伺服器,TCP程序併發伺服器

文章目錄 1,TCP多執行緒併發伺服器 1.1,標頭檔案net.h 1.2,客戶端client.c 1.3,伺服器端server.c 2,TCP多程序併發伺服器 2.1,標頭檔案net.h 2.2,客

零基礎學python:併發伺服器、面向連線、程序執行緒、單程序

面向連線的併發伺服器 只能同時為一個人服務 為了幫助小夥伴們更好的學習Python,小編整理了Python的相關學習視訊及學習路線圖; ,新增小編學習群943752371即可獲取 多程序併發伺服器 多程序伺服器代表:Apache伺服器 主程序中必需

linux(一)------程序併發伺服器實現(fork)

本文實現一個多程序併發伺服器 實現思路: 利用fork()函式實現每有一個client連線時就會建立一個子程序程序與client通訊,父程序負責回收子程序的PCB 直接上程式碼! #include <stdio.h> #i

linux socket程序併發伺服器

/***sever***/ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>

linux fork程序併發伺服器模型之C/C++程式碼實戰

        在很早的文章中, 我們一起聊過伺服器如何與多個客戶端進行通訊, 那時, 我們要麼用select, 要麼用多執行緒, 卻沒有用多程序。 其實, 多程序也可以實現與多個客戶端進行通訊。          如果是在while中迴圈accept,  然後迴圈處理事情

Linux 網路程式設計 全解(四)--------程序併發伺服器執行緒併發伺服器

寫在前面:這個系列也是停滯了20多天了,從今天開始再次步入正軌,以後每個週末都會陸陸續續的更新,這個系列預計完結的時間還會在大約一個月左右,今天靜下心來多整理幾篇。QQ:993650814 正文: 一、多程序併發伺服器     設計思路:當有新的客戶端連線到

TCP客戶端/伺服器網路程式設計------程序併發模型(附帶實現)

多程序併發模型相比同步阻塞迭代模型,多程序併發模型可以避免是程式阻塞在read系統呼叫上。如果沒有客戶端來建立連線,則會阻塞在accept處。一旦某個客戶端連線建立起來,則立即開啟一個新的程序來處理與這個客戶的資料互動。避免程式阻塞在read呼叫,而影響其他客戶端的連線。缺陷

Python學習程序併發寫入同一檔案

最近學習了Python的多程序,想到我的高德API爬蟲那個爬取讀寫速度我就心累,實在是慢,看到多程序可以充分利用CPU核數我就開始完善我的程式碼,不過過程是艱辛的,在此之中出現了很多問題,其中最大的問題是爬取的資料是正確的,但是讀寫到Excel中卻開啟是空,想了半天也沒解決,腦子笨沒辦法,不過我

Python程序併發操作程序池Pool

目錄: multiprocessing模組 Pool類 apply apply_async map close terminate join 程序例項 multiprocessing模組 如果你打算編寫多程序的服務程式,Unix/

Linux 工程式設計——特殊程序殭屍程序、孤兒程序、守護程序

殭屍程序(Zombie Process) 程序已執行結束,但程序的佔用的資源未被回收,這樣的程序稱為殭屍程序。 在每個程序退出的時候,核心釋放該程序所有的資源、包括開啟的檔案、佔用的記憶體等。 但是仍然為其保留一定的資訊,這些資訊主要主要指程序控制塊的資訊(包括程序號、退出狀態、執行時

Python中建立程序的方法,以及併發並行,殭屍程序,孤兒程序的相關概念

一、併發與並行 並行:多個計算機核心在同時處理多個任務,這時多個任務間是並行關係 併發:同時處理多個任務,但是核心在多個任務間不斷地切換,達到好像都在處理執行的效果,但實際一個時間點核心只能處理其中一個任務。 二、程序 程序與執行緒是實現多工程式設計的實施方案 程序與執