1. 程式人生 > >php pcntl_fork 多程序殭屍程序的問題

php pcntl_fork 多程序殭屍程序的問題

因業務需要用到了pcntl_fork 處理多客戶端連線處理資料的需求

但測試下來出現一個問題:

fork 之後, 若等待子程序返回, 那麼程式就會阻塞, 不等待子程序返回, 則會出現殭屍程序

$obj = new service('127.0.0.1', 50000);
$obj->run();

class service {

    private $socket_id;
    private $socket_cid;
    private $pid;

    function __construct($host, $port) {
        $this->socket_id = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if (!$this->socket_id) {
            $this->logs("create socket error");
            return false;
        }
        if (!socket_bind($this->socket_id, $host, $port)) {
            $this->logs(socket_strerror(socket_last_error()));
            socket_close($this->socket_id);
            return false;
        }
        if (!socket_listen($this->socket_id)) {
            $this->logs(socket_strerror(socket_last_error()));
            socket_close($this->socket_id);
            return false;
        }
    }

    public function run() {
        if (!$this->socket_id) {
            $this->logs("create socket error");
            return false;
        }
        $this->logs("Starting...");
        while (true) {
            $this->socket_cid = socket_accept($this->socket_id);
            $ip = "";
            socket_getpeername($this->socket_cid, $ip);
            $this->logs("Client IP: {$ip}");
            if (!is_resource($this->socket_cid)) {
                $this->logs(socket_strerror(socket_last_error()));
                socket_close($this->socket_id);
                return false;
            }
            $this->pid = pcntl_fork();
            if ($this->pid == -1) {
                $this->logs(socket_strerror(socket_last_error()));
                socket_close($this->socket_cid);
                return false;
            } else if ($this->pid) {
                $status = 0;
                $s = pcntl_wait($status, WNOHANG); //等待子程序中斷,防止子程序成為殭屍程序, 但這樣會阻塞, 意思是隻能處理一個客戶端連線, 多個進入排隊
                //$s = pcntl_waitpid(0, $status, WUNTRACED); //如果不等待, 則子程序處理完之後, 沒有對其進行處理, 會成為殭屍程序
                $this->logs("Status: " . $status . ", pcntl_waitpid: " . $s);
            } elseif ($this->pid == 0) { //child process
                $k = 0;
                while (true) {
                    if ($data = socket_read($this->socket_cid, 1024)) {
                        $this->logs("Read Data: {$data}");
                        $flag = socket_write($this->socket_cid, date('Y-m-d H:i:s') . '|已收到');
                        $this->logs("Write Result: {$flag}");
                    }
                    sleep(1);
                    $k++;
                    $this->logs("Wait...\t" . date('Y-m-d H:i:s'));
                    if ($k > 30) {
                        break;
                    }
                }
                socket_close($this->socket_cid);
                exit(1);
            }
        }
        socket_close($this->socket_id);
    }

    /**
     * 打日誌
     * @param string $msg
     * @return int
     */
    private function logs($msg) {
        $logs_filename = LOGS_PATH;
        if (!file_exists($logs_filename)) {
            @mkdir($logs_filename, 0777, true);
        }
        $logs_filename .= date('j') . '.log';
        $logs_data = date('[H:i:s]') . " {$msg}\n";
        return file_put_contents($logs_filename, $logs_data, FILE_APPEND);
    }

    function __destruct() {
        if (is_resource($this->socket_id)) {
            socket_close($this->socket_id);
        }
        if (is_resource($this->socket_cid)) {
            socket_close($this->socket_cid);
        }
    }

}



在網上搜了半天, 這位仁兄的解決辦法是對的(http://blog.csdn.net/e421083458/article/details/22186475), 就是增加訊號處理,

在socket accept之前加上 pcntl_signal(SIGCHLD, SIG_IGN); //如果父程序不關心子程序什麼時候結束,子程序結束後,核心會回收。

也就是在run方法開始處 :)

    public function run() {
        if (!$this->socket_id) {
            $this->logs("create socket error");
            return false;
        }
        pcntl_signal(SIGCHLD, SIG_IGN);
        $this->logs("Starting....");
        ...
      }


相關推薦

php pcntl_fork 程序殭屍程序的問題

因業務需要用到了pcntl_fork 處理多客戶端連線處理資料的需求 但測試下來出現一個問題: fork 之後, 若等待子程序返回, 那麼程式就會阻塞, 不等待子程序返回, 則會出現殭屍程序 $obj = new service('127.0.0.1', 50000);

Kill殺死Linux中的defunct程序(殭屍程序)

一、什麼是defunct程序(殭屍程序)? 在 Linux 系統中,一個程序結束了,但是他的父程序沒有等待(呼叫wait / waitpid)他,那麼他將變成一個殭屍程序。當用ps命令觀察程序的執行狀態時,看到這些程序的狀態列為defunct。殭屍程序是一個早已

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

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

PHP利用程序處理任務(一篇寫得比較容易理解的程序文章)

 PHP多程序一般應用在PHP_CLI命令列中執行php指令碼,不要在web訪問時使用。    多程序處理分解任務一般要比單程序更快。   php檢視是否安裝多程序模組: php -m

使用Phalcon+PHP-FPM構建PHP基於程序的資料庫連線池

之前看到網上有一篇文章說Phalcon和PHP沒有資料庫連線池,而swoole本身提供了很好的資料庫連線池。實際上這是一種誤解,PHP自身早就實現了持久化的資料庫連線。而Phalcon基於zephir寫的資料庫連線介面卡,必然也是支援PHP自身實現的這種資料

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

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

【C/C++】程序殭屍程序

  一個殭屍程序產生的過程是:父程序呼叫fork建立子程序後,子程序執行至其終止。程序終止後有些資訊對於父程序和核心還是很有用的,例如程序的ID號、程序的退出狀態、程序執行的CPU時間等。因此程序執行終止後,系統會回收所有核心分配給它的記憶體、關閉它所開啟的檔案等,但是還會保

以例項全面講解PHP程序程式設計的相關函式的使用,php函式

 PHP有一組程序控制函式(編譯時需要–enable-pcntl與posix擴充套件),使得php能實現跟c一樣的建立子程序、使用exec函式執行程式、處理訊號等功能。     <?php header('content-type:text/html;char

PHP實現程序並行執行指令碼

由於php的程序是不支援多執行緒的,有些場景為了方便以及提高效能,可以用php實現多程序以彌補這個不足: #!/usr/bin/env php < ?php $cmds=array(

php+Socket程序處理速學:防止子程序無限增加

<?php $socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); socket_bind($socket,'127.0.0.1',9090) or die('error'); socket_listen($socket,5); $child =

php swoole 程序傳送微信模板訊息\郵件

   年前接到需求做了一個功能,給快到期的微信使用者傳送模板訊息,提醒續費.    首先拿到快到期的使用者, 每天大概800-2000不等,感覺壓力不是很大,直接foreach 陣列 然後傳送,經常出現請求超時 也就是502的問題,緊接著運營同事提出要針對一大批使用者 推模板

PHP解決程序同時讀寫一個…

/* *flock(file,lock,block) *file 必需,規定要鎖定或釋放的已開啟的檔案 *lock 必需。規定要使用哪種鎖定型別。 *block 可選。若設定為 1 或 true,則當進行鎖定時阻擋其他程序。 *lock *LOCK_SH 要取得共享鎖定(讀取的程式) *LOCK_EX 要取

gdb調試進程線程程序

mage 支持 nbsp rgs 提示 功能 網絡 網絡編程 指令 一、調試的指令   1.list命令     list  linenum  顯示程序第linenum行的周圍的程序     list  function  顯示程序名為function的函數的源程序    

【2017-06-20】Linux應用開發工程師C/C++面試問題之一:Linux線程程序的同步問題

依次 其它 如果 開發工程師 logs 特殊 另一個 特殊情況 發生 參考之一:Linux 線程同步的三種方法 鏈接地址:http://www.cnblogs.com/eleclsc/p/5838790.html 簡要回答: Linux下線程同步最常用的三種方法就是互斥鎖、

php異步執行其他程序

user ajax linux pen ignore curl 設置 缺失 開啟 這裏的“其他程序”,可能是linux命令,可能是其他的php文件。 網上說法有四種。分別為: 1、通過加載頁面的時候通過ajax技術異步請求服務器 2、通過popen()函數 3、通過curl

如何同時打開個應用程序

需要 復制 strong 多個 允許 tro start 並保存 技術分享 每天早上打開電腦後都需要打開多個應用程序,一個一個的打開很麻煩,下面的操作將實現如何同時打開多個應用程序: 1.首先,新建一個txt文件 2.右鍵單擊要打開的應用程序,並點擊屬性,在彈出框中復制目標

CountDownLatch在線程程序中的應用

exception pac 所有 args lar hash oid sys exc 一.CountDownLatch介紹 CountDownLatch是JDK1.5之後引入的,存在於java.util.concurrent包下,能夠使一個線程等待其他線程完成動作後再執行。

ThreadLocal 解決線程程序的並發問題+事務處理

{} cep 程序管理 sta cte read nag lease 管理 1 import java.sql.Connection; 2 import java.sql.SQLException; 3 4 public class TranManager

gdb調試線程程序總結

done sysv php inux 提示信息 pst works his argc gdb調試多線程程序總結 來源 https://www.cnblogs.com/jingzhishen/p/4324071.html 一、多線程調試1. 多線程調試,最重要的幾個命令

使用 GDB 調試進程程序

tin 出現 二進制 nom 主題 rtu 錯誤 virtual pad 使用 GDB 調試多進程程序 來源 https://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/index.html GDB 是 linux 系統