php中使用fsockopen实现异步请求

转自:  https://www.yisu.com/zixun/367919.html

还有一篇:   https://www.laruence.com/2008/04/16/98.html

php中怎么使用fsockopen实现异步请求,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

php执行一段程序,有可能几毫秒就执行完毕,也有可能耗时较长。

例如,用户下单这个事件,如果调用了些第三方服务进行发邮件、短信、推送等通知,可能导致前端一直在等待。

而有的时候,我们并不关心这些耗时脚本的返回结果,只要执行就行了。这时候就需要采用异步的方式执行。

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

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

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$fp fsockopen("www.example.com", 80, $errno$errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
else {
    $out "GET /backend.php   HTTP/1.1\r\n";
    $out .= "Host: www.example.com\r\n";
    $out .= "Connection: Close\r\n\r\n";
  
    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增加配置

1
2
# 忽略客户端中断
fastcgi_ignore_client_abort on;

2)fwrite之后使用usleep函数休眠20毫秒:

1
usleep(20000);

后来测试就没有发现失败的情况了。

附上完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?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\r\n";
        $out .= "Host:${host}\r\n";
        $out .= "Content-type:application/x-www-form-urlencoded\r\n";
        $out .= "Content-length:".strlen($data)."\r\n";
        $out .= "Connection:close\r\n\r\n";
        $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\r\n";
        $out .= "Host:${host}\r\n";
        $out .= "Connection:close\r\n\r\n";
        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);
    }
    
}
?>
posted @   仁义礼智信的  阅读(235)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示