在开发中遇到过这样的问题(我是在支付宝回调的时候,处理的业务逻辑有点多),某段程序执行很慢,但是这又涉及到用户体验,这时候我们就会想如果我先返回给用户成功的提示,然后我在服务器上再去慢慢执行我的代码不就两全齐美了吗-----这就是我理解的异步。
PHP是支持socket编程的,就是fsockopen函数,
函数说明:fsockopen — 打开一个网络连接或者一个Unix套接字连接
fscokopen会返回一个到远程主机连接的句柄。你可以像使用fopen返回的句柄一样,对她进行写fwrite,读取fgets, fread等操作。
1:要使用这个函数,首先就要确认自己服务器上配置的是支持fsock的,找到php.ini,修改allow_url_fopen =on,还有一个就是打开extension=php_openssl.dll扩展
2:如果没有安装openssl扩展,则先安装扩展,流程如下
(1) 先安装依赖包:yum install openssl openssl-devel
(2) 进入PHP安装包里的OpenSSL文件夹,根据个人的安装包位置不同,此处是
cd /home/local/php.5.6.25/ext/openssl/phpize
(3) 可能报错:Cannot find config.m4. Make sure that you run /usr/local/bin/phpize
in the top level source directory of the module,
(4) 在当前目录下执行:mv config0.m4 config.m4
(5) 重新phpize
./configure --with-php-config=/usr/local/php/bin/php-config(php-config文件的路径)
(6) 编译安装 make&&make install
(7) 将openssl.so复制到PHP扩展文件夹中
(8) 修改php.ini中 extesion=openssl.so
3:接下来就是编写方法和PHP脚本了(贴上本人测试代码:post请求)
//测试发fsock异步调用PHP
/**fsockopen 抓取页面
* @parem $url 网页地址 host 主机地址
* @parem $port 网址端口 默认80
* @parem $t 脚本请求时间 默认30s
* @parem $method 请求方式 get/post
* @parem $data 如果单独传数据为 post 方式
* @return 返回请求回的数据
* */
public function luelue()
{
$url = "http://seckill.com/hehe.php"; #url 地址必须 http://xxxxx
$port=80;
$t=30;
$method='post';
$data = array(
'id'=>'1',
'content'=>'这是第2次测试',);
$info=parse_url($url);
$fp = fsockopen($info["host"],$port, $errno, $errstr,$t);
// 判断是否有数据
if(isset($data) && !empty($data))
{
$query = http_build_query($data); // 数组转url 字符串形式
}else
{
$query=null;
}
// 如果用户的$url "http://www.manongjc.com/"; 缺少 最后的反斜杠
if(!isset($info['path']) || empty($info['path']))
{
$info['path']="/index.html";
}
// 判断 请求方式
if($method=='post')
{
$head = "POST ".$info['path']." HTTP/1.0".PHP_EOL;
}else
{
$head = "GET ".$info['path']."?".$query." HTTP/1.0".PHP_EOL;
}
$head .= "Host: ".$info['host'].PHP_EOL; // 请求主机地址
$head .= "Referer: http://".$info['host'].$info['path'].PHP_EOL;
if(isset($data) && !empty($data) && ($method=='post'))
{
$head .= "Content-type: application/x-www-form-urlencoded".PHP_EOL;
$head .= "Content-Length: ".strlen(trim($query)).PHP_EOL;
$head .= PHP_EOL;
$head .= trim($query);
}else
{
$head .= PHP_EOL;
}
$write = fputs($fp, $head);
//写入文件(可安全用于二进制文件)。 fputs() 函数是 fwrite() 函数的别名
//不等待返回结果,直接return true
echo json_encode(['status'=>200,'message'=>'success']);
// while (!feof($fp))
// {
// $line = fread($fp,4096);
// echo $line;
// }
}
所调用的PHP脚本
<?php
$data=$_POST;
define('DB_HOST','你的数据库host');
define('DB_USER','你的数据库用户名');
define('DB_PASS','数据库密码');
define('DB_NAME','数据库名字');
define('DB_CHAR','utf8');
$db = @mysqli_connect(DB_HOST,DB_USER,DB_PASS);
if(mysqli_connect_errno($db)){
exit('对不起,连接错误哦'.mysqli_connect_error($db));
}
//选择数据库名
mysqli_select_db($db,DB_NAME);
//选择字符集
mysqli_set_charset($db,DB_CHAR);
$sql="update test set taa='".$data['content']."' where id=".$data['id'];
sleep(10); //用户观察是不是先返回再更新的
$res=mysqli_query($db,$sql);
var_dump($res);
还有一个问题就是,当客户端断开连接以后。也就是接口发送出调用PHP脚本请求后,立即关闭了连接,那么可能会引起服务器端正在执行的脚本退出。
在 PHP 内部,系统维护着连接状态,其状态有三种可能的情况:
* 0 – NORMAL(正常)
* 1 – ABORTED(异常退出)
* 2 – TIMEOUT(超时)
(1)当 PHP 脚本正常地运行 NORMAL 状态时,连接为有效。
(2)当客户端中断连接时,ABORTED 状态的标记将会被打开。远程客户端连接的中断通常是由用户点击 STOP 按钮导致的。
(3)当连接时间超过 PHP 的时限(请参阅 set_time_limit() 函数)时,TIMEOUT 状态的标记将被打开。
1:客户端断开连接中断脚本
脚本是否需要在客户端中断连接时退出是可以设置的,(默认的情况是当远程客户端连接 中断时脚本将会退出)。该处理过程可由 php.ini 的 ignore_user_abort 或由 Apache .conf 设置中对应的“php_value ignore_user_abort”以及 ignore_user_abort() 函数来控制。如果没有告诉 PHP 忽略用户的中断,脚本将会被中断,除非通过 register_shutdown_function() 设置了关闭触发函数。
2:脚本执行时间超时中断
脚本也有可能被内置的脚本计时器中断。默认的超时限制为 30 秒。这个值可以通过设置 php.ini 的 max_execution_time 或 Apache .conf 设置中对应的“php_value max_execution_time”参数或者 set_time_limit() 函数来更改。当计数器超时的时候,脚本将会类似于以上连接中断的情况退出,先前被注册过的关闭触发函数也将在这时被执行。在该关闭触发函数中,可以通过调 用 connection_status() 函数来检查超时是否导致关闭触发函数被调用。如果超时导致了关闭触发函数的调用,该函数将返回 2。
需要注意的一点是 ABORTED 和 TIMEOUT 状态可以同时有效。这在告诉 PHP 忽略用户的退出操作时是可能的。PHP 将仍然注意用户已经中断了连接但脚本仍然在运行的情况。如果到了运行的时间限制,脚本将被退出,设置过的关闭触发函数也将被执行。在这时会发现函数 connection_status() 返回 3。
所以还在要触发的脚本中指明:
ignore_user_abort(TRUE); //如果客户端断开连接,不会引起脚本abort
set_time_limit(0);//取消脚本执行延时上限
或者,也可以使用:
register_shutdown_function(callback fuction[, parameters]);//注册脚本退出时执行的函数
本文参考文章:
1: http://www.laruence.com/2008/04/16/98.html
2: https://www.cnblogs.com/xuey/p/8463009.html
网友评论