PHP异步请求 fsockopen() 方法详解

袁志蒙 789次浏览

摘要:正常情况下,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秒";


随机内容

表情

共1条评论
  • 网友评论:

    实用

    2023-10-07 20:22:43 回复

    点击加载