加入收藏 | 设为首页 | 会员中心 | 我要投稿 鹰潭站长网 (https://www.0701zz.cn/)- 图像处理、低代码、云通信、数据工具、物联设备!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

php中使用fsockopen实现异步请求

发布时间:2022-06-30 09:53:18 所属栏目:PHP教程 来源:互联网
导读:php执行一段程序,有可能几毫秒就执行完毕,也有可能耗时较长。 例如,用户下单这个事件,如果调用了些第三方服务进行发邮件、短信、推送等通知,可能导致前端一直在等待。 而有的时候,我们并不关心这些耗时脚本的返回结果,只要执行就行了,这时候就需要采
  php执行一段程序,有可能几毫秒就执行完毕,也有可能耗时较长。
 
  例如,用户下单这个事件,如果调用了些第三方服务进行发邮件、短信、推送等通知,可能导致前端一直在等待。
 
  而有的时候,我们并不关心这些耗时脚本的返回结果,只要执行就行了,这时候就需要采用异步的方式执行。
 
  众所周知,PHP没有直接支持多线程这种东西,我们可以采用折衷的方式实现,这里主要说的就是fsockopen。
 
  通过fsockopen发送请求并忽略返回结果,程序可以马上返回。
 
  示例代码:
 
  $fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
   
  if (!$fp) {
   
      echo "$errstr ($errno)<br />n";
   
  } else {
   
      $out = "GET /backend.php   HTTP/1.1rn";
   
      $out .= "Host: www.example.comrn";
   
      $out .= "Connection: Closernrn";
   
     
   
      fwrite($fp, $out);
   
      /*忽略执行结果
   
      while (!feof($fp)) {
   
          echo fgets($fp, 128);
   
      }*/
   
      fclose($fp);
   
  }
  需要注意的是我们需要手动拼出header头信息,通过打开注释部分,可以查看请求返回结果,但这时候又变成同步的了,因为程序会等待返回结果才结束。
 
  实际测试的时候发现,不忽略执行结果,调试的时候每次都会成功发送sock请求;但忽略执行结果,经常看到没有成功发送sock请求。查看nginx日志,发现很多状态码为499的请求。
 
  后来找到了原因:
 
  fwrite之后马上执行fclose,nginx会直接返回499,不会把请求转发给php处理。
 
  客户端主动端口请求连接时,NGINX 不会将该请求代理给上游服务(FastCGI PHP 进程),这个时候 access log 中会以 499 记录这个请求。
 
  解决方案:
 
  1)nginx.conf增加配置
 
  # 忽略客户端中断
 
  fastcgi_ignore_client_abort on;
 
  2)fwrite之后使用usleep函数休眠20毫秒:
 
  usleep(20000);
 
  后来测试就没有发现失败的情况了。
 
  附上完整代码:
 
  <?php
   
  /**
   
   * 工具类
   
   * */
   
  class FsockService {
   
        
   
      public static function post($url, $param){
   
          $host = parse_url($url, PHP_URL_HOST);
   
          $port = 80;
   
          $errno = '';
   
          $errstr = '';
   
          $timeout = 30;
   
          $data = http_build_query($param);
   
          // create connect
   
          $fp = fsockopen($host, $port, $errno, $errstr, $timeout);
   
          if(!$fp){
   
              return false;
   
          }
   
          // send request
   
          $out = "POST ${url} HTTP/1.1rn";
   
          $out .= "Host:${host}rn";
   
          $out .= "Content-type:application/x-www-form-urlencodedrn";
   
          $out .= "Content-length:".strlen($data)."rn";
   
          $out .= "Connection:closernrn";
   
          $out .= "${data}";
   
          fwrite($fp, $out);
   
          //忽略执行结果;否则等待返回结果
   
  //        if(APP_DEBUG === true){
   
          if(false){
   
              $ret = '';
   
              while (!feof($fp)) {
   
                  $ret .= fgets($fp, 128);
   
              }
   
          }
   
          usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499
   
          fclose($fp);
   
      }
   
      public static function get($url, $param){
   
          $host = parse_url($url, PHP_URL_HOST);
   
          $port = 80;
   
          $errno = '';
   
          $errstr = '';
   
          $timeout = 30;
   
          $url = $url.'?'.http_build_query($param);
   
          // create connect
   
          $fp = fsockopen($host, $port, $errno, $errstr, $timeout);
   
          if(!$fp){
   
              return false;
   
          }
   
          // send request
   
          $out = "GET ${url} HTTP/1.1rn";
   
          $out .= "Host:${host}rn";
   
          $out .= "Connection:closernrn";
   
          fwrite($fp, $out);
   
          //忽略执行结果;否则等待返回结果
   
  //        if(APP_DEBUG === true){
   
          if(false){
   
              $ret = '';
   
              while (!feof($fp)) {
   
                  $ret .= fgets($fp, 128);
   
              }
   
          }
   
          usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499
   
          fclose($fp);
   
      }
   
       
   
  }
   
  ?>
 

(编辑:鹰潭站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读