摘要:正常情况下,PHP执行的都是同步请求,代码自上而下依次执行,但有些场景如发送邮件、执行耗时任务等操作时就不适用于同步请求,只能使用异步处理请求。场景要求:客户端调用服...
正常情况下,PHP执行的都是同步请求,代码自上而下依次执行,但有些场景如发送邮件、执行耗时任务等操作时就不适用于同步请求,只能使用异步处理请求。
场景要求:
客户端调用服务器 a.php 接口,需要执行一个长达 10s-20s 不等的耗资源操作,假如客户端响应请求时间为5秒(请求响应超时时间),5s 以上无回复即断开连接。
解决设想:
客户端调用 a.php 之后,a.php 执行异步多线程操作调用 b.php,a.php 调用成功后即刻反馈给客户端回执,b.php 自动执行耗资源操作。
方案:
利用 fsockopen() 方法解决PHP异步请求
1.封装异步请求函数 asyncRequest(),代码如下:
/**
* php异步请求
* @param $url string 请求Url
* @param $post array POST参数
* @return string
*/
function asyncRequest($url, $post = array()){
$matches = parse_url($url);
!isset($matches['host']) && $matches['host'] = '';
!isset($matches['path']) && $matches['path'] = '';
!isset($matches['query']) && $matches['query'] = '';
!isset($matches['port']) && $matches['port'] = 80;
P($matches);
$host = $matches['host'];
$port = $matches['port'];
$path = $matches['path'] ? $matches['path'].($matches['query'] ? '?'.$matches['query'] : '') : '/';
$post = $post && is_array($post) ? http_build_query($post) : '';
$errno = 0;
$errstr = '';
$timeout = 30; //连接超时时间(S)
if(function_exists('fsockopen')) {
$fp = @fsockopen($host, $port, $errno, $errstr, $timeout);
} elseif (function_exists('pfsockopen')) {
$fp = @pfsockopen($host, $port, $errno, $errstr, $timeout);
} elseif (function_exists('stream_socket_client')) {
$fp = @stream_socket_client('tcp://'.$host.':'.$port, $errno, $errstr, $timeout);
} else {
$fp = false;
}
if (!$fp) {
return '连接失败';
}
if ($errno || !$fp) {
return $errstr;
}
$out = "POST $path HTTP/1.1\r\n";
$out .= "Accept: */*\r\n";
//$out .= "Referer: $Referer\r\n";
$out .= "Accept-Language: zh-cn\r\n";
$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
$out .= "User-Agent: ".$_SERVER['HTTP_USER_AGENT']."\r\n";
$out .= "Host: $host\r\n";
$out .= 'Content-Length: '.strlen($post)."\r\n";
$out .= "Connection: Close\r\n";
$out .= "Cache-Control: no-cache\r\n";
$out .= $post;
stream_set_blocking($fp, false); //非阻塞
stream_set_timeout($fp, $timeout);//响应超时时间(S)
$result = @fwrite($fp, $out);
@fclose($fp);
return $result;
}2.正常接口 a.php,如下:
$url = 'http://localhost/b.php'; $param = array( 'istest' => 1, ); $asyncData = asyncRequest($url, $param); echo 'a.php success';
3.耗时接口 b.php,如下:
set_time_limit(0); ignore_user_abort(true);//设置与客户机断开是否会终止执行 fastcgi_finish_request();//提高请求的处理速度 sleep(15); echo "耗时15秒";

网友评论:
实用
2023-10-07 20:22:43 回复