怎么实现PHP异步

2019-06-17  本文已影响0人  宸风如苏
在开发中遇到过这样的问题(我是在支付宝回调的时候,处理的业务逻辑有点多),某段程序执行很慢,但是这又涉及到用户体验,这时候我们就会想如果我先返回给用户成功的提示,然后我在服务器上再去慢慢执行我的代码不就两全齐美了吗-----这就是我理解的异步。
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

上一篇 下一篇

猜你喜欢

热点阅读