正常狀況下,PHP執行的都是同步請求,代碼自上而下依次執行,但有些場景如發送郵件、執行耗時任務等操做時就不適用於同步請求,只能使用異步處理請求。php
客戶端調用服務器a.php接口,須要執行一個長達10s-20s不等的耗資源操做,假如客戶端響應請求時間爲5秒(請求響應超時時間),5s以上無回覆即斷開鏈接。服務器
客戶端調用a.php以後,a.php執行異步多線程操做調用b.php,a.php調用成功後即刻反饋給客戶端回執,b.php自動執行耗資源操做。多線程
利用fsockopen()方法解決PHP異步請求app
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,以下socket
/** * 正常接口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,以下async
/** * 耗時接口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秒"; }
上述實例即爲簡單的測試接口部分代碼,根據本身需求作修改便可;tcp