参考网址

https://www.cnblogs.com/wenzheshen/p/10213480.html

正常情况下,PHP 执行的都是同步请求,代码自上而下依次执行,但是有些场景如发送邮件、执行耗时任务等操作就不适合同步请求,只能使用异步处理请求。

场景要求

客户端调用服务器 a.php 接口,需要执行一个长达 10s - 20s 不等的耗资源操作,假如客户端响应请求时间为 5s (请求响应超时时间),5s 以上无回复即断开连接。

解决设想

客户端调用 a.php 之后, a.php 执行异步多线程操作调用 b.phpa.php 调用成功后即刻反馈给客户端回执, b.php 自动执行耗资源操作。

方案

利用 fsockopen() 方法解决PHP异步请求。

  1. 封装异步请求函数 asyncRequest() ,代码如下:
  1. /**
  2. * php异步请求
  3. * @param $host string 主机地址
  4. * @param $path string 路径
  5. * @param $param array 请求参数
  6. * @return string
  7. */
  8. private static function asyncRequest($host, $path, $param = array()){
  9. $query = isset($param) ? http_build_query($param) : '';
  10. Bd_Log::debug($query);
  11. $port = 80;
  12. $errno = 0;
  13. $errstr = '';
  14. $timeout = 30; //连接超时时间(S)
  15. $fp = @fsockopen($host, $port, $errno, $errstr, $timeout);
  16. //$fp = stream_socket_client("tcp://".$host.":".$port, $errno, $errstr, $timeout);
  17. if (!$fp) {
  18. Bd_Log::debug('连接失败');
  19. return '连接失败';
  20. }
  21. if ($errno || !$fp) {
  22. Bd_Log::debug($errstr);
  23. return $errstr;
  24. }
  25. stream_set_blocking($fp,0); //非阻塞
  26. stream_set_timeout($fp, 1);//响应超时时间(S)
  27. $out = "POST " . $path . " HTTP/1.1\r\n";
  28. $out .= "host:" . $host . "\r\n";
  29. $out .= "content-length:" . strlen($query) . "\r\n";
  30. $out .= "content-type:application/x-www-form-urlencoded\r\n";
  31. $out .= "connection:close\r\n\r\n";
  32. $out .= $query;
  33. $result = @fputs($fp, $out);
  34. @fclose($fp);
  35. return $result;
  36. }

实例

正常接口 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秒";
    }