• php中使用fsockopen实现异步请求


    php执行一段程序,有可能几毫秒就执行完毕,也有可能耗时较长。例如,用户下单这个事件,如果调用了些第三方服务进行发邮件、短信、推送等通知,可能导致前端一直在等待。而有的时候,我们并不关心这些耗时脚本的返回结果,只要执行就行了。这时候就需要采用异步的方式执行。

    众所周知,PHP没有直接支持多线程这种东西。我们可以采用折衷的方式实现。这里主要说的就是fsockopen。

    通过fsockopen发送请求并忽略返回结果,程序可以马上返回。

    示例代码:

    $fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
    if (!$fp) {
        echo "$errstr ($errno)<br />
    ";
    } else {
        $out = "GET /backend.php   HTTP/1.1
    ";
        $out .= "Host: www.example.com
    ";
        $out .= "Connection: Close
    
    ";
     
        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.1
    ";
            $out .= "Host:${host}
    ";
            $out .= "Content-type:application/x-www-form-urlencoded
    ";
            $out .= "Content-length:".strlen($data)."
    ";
            $out .= "Connection:close
    
    ";
            $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.1
    ";
            $out .= "Host:${host}
    ";
            $out .= "Connection:close
    
    ";
    
            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);
        }
       
    }
    
    ?>
    

    参考:
    1、PHP实现异步调用方法研究 | 风雪之隅
    http://www.laruence.com/2008/04/14/318.html
    2、PHP fsockopen 异步调用接口在nginx上偶尔实效的情况 - 张炜施 - 博客园
    http://www.cnblogs.com/zhangweishi/p/5306813.html
    3、php 利用fsockopen GET/POST 提交表单及上传文件 - 傲雪星枫 - 博客频道 - CSDN.NET
    http://blog.csdn.net/fdipzone/article/details/11712607
    4、关于PHP的异步调用 - 浮云比翼 - 博客园
    http://www.cnblogs.com/fuyunbiyi/archive/2013/03/27/2985089.html

  • 相关阅读:
    海量数据与布隆过滤
    Flink History Job
    golang and intellij
    maven中如何得到父工程的位置
    maven中进行go的编译
    hbase表的写入
    Storm之tickTuple
    storm-kafka版本不匹配的问题
    (17)zabbix自定义用户key与参数User parameters
    (16)zabbix history trends历史与趋势数据详解
  • 原文地址:https://www.cnblogs.com/52fhy/p/6209479.html
Copyright © 2020-2023  润新知