zoukankan      html  css  js  c++  java
  • php 使用fsockopen 发送http请求

    需求背景

    在公司开发这么一个需求,每天三次定时催付待客服催付状态的订单,设定每天15、16、17点三次执行job任务来给一批订单打电话催付,需要三个时间点都把待客服催付的订单拨打一遍电话,根据数据组统计,大概每天需要催付的订单数量在6000左右,对接第三方电话呼叫业务,拿到订单信息来呼叫。

    测试状态

    拿500个订单手动执行第一波测试,发现500个订单催付完毕需要30多分钟,那么6000个订单按照需求催付时间点是完全不够的,半小时500个,一小时最多1000个。

    初步排查,是由于使用php  curl请求导致每一次遍历的请求时间慢,由于curl请求最短的time时间耗时是1秒,那么一小时3600秒也是不够呼完这6000单。

    解决方案

    一、在遍历循环的时候把每次请求的量丢入消费系统(队列),然后根据开启多个消费者来消费这些(上线迫在眉睫,来不及)

    二、有没有类似curl更快的方案,发现了fsockopen,按照使用方法配置完500个订单,遍历完成只需要18秒。

    需求代码

      /**
         * 通过订单信息组装呼叫信息
         * @param array $order
         * @return array
         */
        private function getCallInfoByOrder ($order = [])
        {
            $order_ext  = OrderExt::model()->getPrimary($order['order_id']);
            $point      = (isset($order_ext['app_ver'])&&version_compare($order_ext['app_ver'],Tools::PRICE_COMPARE_VERSION,">="));
            $pay_detail     = json_decode($order['pay_detail'], true);
            $call_text      = OrderPayRemainService::organizeHeLiText($order['create_time'], $pay_detail['cash'], $point);
            return ['phone' => $order['phone'], 'call_text' => $call_text];
        }
    
        //开始呼叫
        private function toCall ($call_info)
        {
            $params = $this->formatGetParams($call_info);
            EdjLog::info(__METHOD__ .'he li to call info' . json_encode($call_info));
           $this->doCurlGetRequest(self::CALL_API_URL, $params, $call_info);
        }
    
        //拨号请求
        private function doCurlGetRequest($url, $data = [],  $call_info = []){
            if($url == "" || empty($data)){
                return false;
            }
            $response = $this->fsockopen_request($url,$data);
    
    //        $response_arr = explode("
    ", $response);
    //
    //        if (in_array(self::TOOKEN_INVALID,$response_arr)) {
    //            EdjLog::info(__METHOD__ .'he li accessToken expire' . json_encode($call_info));
    //            $this->redis->del(self::ACCESS_TONEN_CACHE_KEY);
    //            $this->toCall($call_info);
    //        }   $response_arr = explode("
    ", $response);
    
            return true;
        }
     private function fsockopen_request($URL,$data, $referrer="") {
    EdjLog::info(__METHOD__ .'he li request url:' . $URL.'-data:'.json_encode($data));
    $URL_Info = parse_url($URL);
    foreach($data as $key=>$value)
    $values[] = "$key=" . urlencode($value);
    $data_string = implode("&",$values);
    if(!isset($URL_Info["port"]))
    $URL_Info["port"] = 80;
    $request = '';
    $request.="POST ".$URL_Info["path"]." HTTP/1.1 ";
    $request.="Host: ".$URL_Info["host"]." ";
    $request.="Referer: $referrer ";
    $request.="Content-type: application/x-www-form-urlencoded ";
    $request.="Content-length: ".strlen($data_string)." ";
    $request.="Connection: close ";
    $request.=" ";
    $request.=$data_string." ";

    $fp = fsockopen($URL_Info["host"],$URL_Info["port"],$errno, $errstr);
    if (!$fp) {
    EdjLog::info('socket_open error:'.json_encode($data). "Error: $errstr ($errno)");
    } else {
    stream_set_blocking($fp, true);//开启了非阻塞模式
    fputs($fp, $request);
    fclose($fp);
    usleep(400000); //等待500ms
    EdjLog::info('socket_open success:'.json_encode($data));
    }
    // $result = '';
    // while(!feof($fp)) {
    //
    // $response = fgets($fp, 512);
    // if (!is_numeric(trim($response))) {
    // continue;
    // }
    // $result.= $response;
    // }

    // return $result;
    }
    
    

    完整说明

    <?php 
      $srv_ip = '192.168.1.5';//你的目标服务地址. 
      $srv_port = 80;//端口 
      $url = 'http://localhost/fsock.php'; //接收你post的URL具体地址  
      $fp = ''; 
      $errno = 0;//错误处理 
      $errstr = '';//错误处理 
      $timeout = 10;//多久没有连上就中断 
      $post_str = "username=demo&password=hahaha";//要提交的内容. 
      //打开网络的 Socket 链接。 
      $fp = fsockopen($srv_ip,$srv_port,$errno,$errstr,$timeout); 
      if (!$fp){ 
       echo('fp fail'); 
      } 
      $content_length = strlen($post_str); 
      $post_header = "POST $url HTTP/1.1
    "; 
      $post_header .= "Content-Type: application/x-www-form-urlencoded
    "; 
      $post_header .= "User-Agent: MSIE
    "; 
      $post_header .= "Host: ".$srv_ip."
    "; 
      $post_header .= "Content-Length: ".$content_length."
    "; 
      $post_header .= "Connection: close
    
    "; 
      $post_header .= $post_str."
    
    "; 
      fwrite($fp,$post_header); 
     
      $inheader = 1; 
      while(!feof($fp)){//测试文件指针是否到了文件结束的位置 
       $line = fgets($fp,1024); 
       //去掉请求包的头信息 
       if ($inheader && ($line == "
    " || $line == "
    ")) { 
             $inheader = 0; 
        } 
        if ($inheader == 0) { 
          echo $line; 
        } 
      } 
      fclose($fp); 
      unset ($line); 
    ?> 

    其它博文

    https://blog.csdn.net/navioo/article/details/82771663

  • 相关阅读:
    解决 Mac launchpad 启动台 Gitter 图标无法删除的问题
    React 与 React-Native 使用同一个 meteor 后台
    解决 React-Native mac 运行报错 error Failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65. To debug build logs further, consider building your app with Xcode.app, by ope
    一行命令更新所有 npm 依赖包
    swift学习笔记
    IOS语言总结
    focusSNS学习笔记
    别小看锤子,老罗真的很认真
    windowsphone开发页面跳转到另一个dll中的页面
    【令人振奋】【转】微软潘正磊谈DevOps、Visual Studio 2013新功能、.NET未来
  • 原文地址:https://www.cnblogs.com/wt645631686/p/11360148.html
Copyright © 2011-2022 走看看