参考网址
https://www.cnblogs.com/wenzheshen/p/10213480.html
正常情况下,PHP 执行的都是同步请求,代码自上而下依次执行,但是有些场景如发送邮件、执行耗时任务等操作就不适合同步请求,只能使用异步处理请求。
场景要求
客户端调用服务器 a.php
接口,需要执行一个长达 10s - 20s 不等的耗资源操作,假如客户端响应请求时间为 5s (请求响应超时时间),5s 以上无回复即断开连接。
解决设想
客户端调用 a.php
之后, a.php
执行异步多线程操作调用 b.php
, a.php
调用成功后即刻反馈给客户端回执, b.php
自动执行耗资源操作。
方案
利用 fsockopen()
方法解决PHP异步请求。
- 封装异步请求函数
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秒";
}