1. 程式人生 > >PHP非同步請求之fsockopen()方法詳解

PHP非同步請求之fsockopen()方法詳解

正常情況下,PHP執行的都是同步請求,程式碼自上而下依次執行,但有些場景如傳送郵件、執行耗時任務等操作時就不適用於同步請求,只能使用非同步處理請求。

場景要求:

客戶端呼叫伺服器a.php介面,需要執行一個長達10s-20s不等的耗資源操作,假如客戶端響應請求時間為5秒(請求響應超時時間),5s以上無回覆即斷開連線。

解決設想:

客戶端呼叫a.php之後,a.php執行非同步多執行緒操作呼叫b.php,a.php呼叫成功後即刻反饋給客戶端回執,b.php自動執行耗資源操作。

方案:

利用fsockopen()方法解決PHP非同步請求

1.封裝非同步請求函式asyncRequest(),程式碼如下:

/**
     * php非同步請求
     * @param $host string 主機地址
     * @param $path string 路徑
     * @param $param array 請求引數
     * @return string
     */
    private static function asyncRequest($host, $path, $param = array()){

        $query = isset($param) ? http_build_query($param) : '';
        Bd_Log
::debug($query); $port = 80; $errno = 0; $errstr = ''; $timeout = 30; //連線超時時間(S) $fp = @fsockopen($host, $port, $errno, $errstr, $timeout); //$fp = stream_socket_client("tcp://".$host.":".$port, $errno, $errstr, $timeout); if (!$fp) { Bd_Log
::debug('連線失敗'); return '連線失敗'; } if ($errno || !$fp) { Bd_Log::debug($errstr); return $errstr; } stream_set_blocking($fp,0); //非阻塞 stream_set_timeout($fp, 1);//響應超時時間(S) $out = "POST " . $path . " HTTP/1.1\r\n"; $out .= "host:" . $host . "\r\n"; $out .= "content-length:" . strlen($query) . "\r\n"; $out .= "content-type:application/x-www-form-urlencoded\r\n"; $out .= "connection:close\r\n\r\n"; $out .= $query; $result = @fputs($fp, $out); @fclose($fp); return $result; }

例項:

正常介面a.php,如下

    /**
     * 正常介面a.php
     * @param $host string 主機地址
     * @param $path string 路徑
     * @param $param array 請求引數
    */
  public function a(){
       $param = array(
           'XXX' => $XXX,
        );
        $asyncData = $this->asyncRequest( $host, $path ,$param);

        echo'a.php success'      
  }

耗時介面b.php,如下

    /**
     * 耗時介面b.php,依次輸出三種結果
    */
    public function b(){
    
      set_time_limit(0);
        ignore_user_abort(true);//設定與客戶機斷開是否會終止執行
        fastcgi_finish_request();//提高請求的處理速度
  
        sleep('30');
        echo "耗時30秒";

        sleep('20');
        echo "耗時20秒";

        sleep('10');
        echo "耗時10秒";
    }

 

上述例項即為簡單的測試介面部分程式碼,根據自己需求做修改即可;