技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> PHP --> fsockopen 异步处理

fsockopen 异步处理

浏览:9030次  出处信息

    前面参与一项目,逻辑处理比较多,所以采用异步处理。

    因为之前采用异步处理时 Web 服务器是 Apache,而这次测试时也是,到把代码更新到服务器上时,执行死活不成功。折腾一番之后,才记起服务器上的 Web 服务器是 Nginx。试着从这个角度查找原因,找到如下这篇文章:

    FROM: 有关fsockopen相关随笔

    测试环境,从本机(Windows)访问内外一台 Linux 服务器(此服务器装的是 Nginx)。

     index.php 代码:


1 使用HTTP 1.1 协议请求

function asyn_sendmail() {
    $ip = '192.168.1.45';
    $url = '/index.php';
    $fp = fsockopen($ip, 80, $errno, $errstr, 5);
    if (!$fp) {
        echo "$errstr ($errno)
\\n"; } $end = "\\r\\n"; $input = "GET $url HTTP/1.1$end"; //如果不加下面这一句,会返回一个 HTTP400 错误 //$input.="Host: $ip$end"; //如果不加下面这一句,请求会阻塞很久 //$input.="Connection: Close$end"; $input.="$end"; fputs($fp, $input); $html = ''; while (!feof($fp)) { $html.=fgets($fp); } fclose($fp); writelog($html); echo $html; } function writelog($message) { $path = 'log.txt'; $handler = fopen($path, 'w+b'); if ($handler) { $success = fwrite($handler, $message); fclose($handler); } } asyn_sendmail();

    如果注释了 $input.="Host: $ip$end"; 这一句,则会得到一个 404 错误,log.txt 内容如下:

HTTP/1.1 400 Bad Request
Server: nginx/0.8.46
Date: Fri, 30 Dec 2011 02:11:45 GMT
Content-Type: text/html
Content-Length: 173
Connection: close


400 Bad Request


nginx/0.8.46

    说明:使用 HTTP 1.1 连接,则必须加上 Host请 求表头。

     如果加上了没有注释 $input.="Host: $ip$end"; 这一句 ,则请求成功,log.txt 内容如下:

HTTP/1.1 200 OK
Server: nginx/0.8.46
Date: Fri, 30 Dec 2011 02:20:49 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.3.8
1
0
0

    返回成功,但是不明白为什么服务器返回内容多了2个 0 (后来网上查询资料发现,这是因为服务器使用了 chunked 输出所致,用 Wireshark 抓包可清晰看到其细节)。如果不加 $input.="Connection: Close$end"; 这一句 ,则 HTTP 请求会阻塞很久(在这一句 fgets($fp) 阻塞)。

2 不指定 HTTP 版本

\\n";
    }
    $end = "\\r\\n";
    $input = "GET $url$end";
    $input.="$end";
    fputs($fp, $input);
    $html = '';
    while (!feof($fp)) {
        $html.=fgets($fp);
    }
    fclose($fp);
    writelog($html);
    echo $html;
}
function writelog($message) {
    $path = 'log.txt';
    $handler = fopen($path, 'w+b');
    if ($handler) {
        $success = fwrite($handler, $message);
        fclose($handler);
    }
}
asyn_sendmail();
?>

    请求立刻返回,没有阻塞,返回内容如下:

1

    注意:返回内容中没有http标头,且没有被阻塞。

    参考上面,代码中,发送到头部信息中正是少了第一段中提到的 $input.="Connection: Close$end";,添加上,问题解决。

    总结:

  • HTTP 1.0, Apache Web 服务器中 $input.="Connection: Close$end"; 与 $input.="Connection: Close$end" 可都不需要。
  • HTTP 1.0, Nginx Web 服务器中 $input.="Connection: Close$end"; 与 $input.="Connection: Close$end" 都必需。
  • HTTP 1.1, Apache Web 服务器中 $input.="Connection: Close$end"; 必须要,$input.="Connection: Close$end" 可不用。
  • HTTP 1.1, Nginx Web 服务器中 $input.="Connection: Close$end"; 与 $input.="Connection: Close$end" 都必需。
  •     fsockopen 上采用 POST 方法的代码:

    $domain = "localhost";
    $url = '/tool/async-test.php';
    $param = "a=1&b=2&c=3&d=4";
    $header = "POST $url HTTP/1.1\\r\\n";
    $header .= "Host: $domain\\r\\n";
    $header .= "Content-Type:application/x-www-form-urlencoded\\r\\n";
    $header .= "Content-Length:" . strlen($param) . "\\r\\n\\r\\n";
    $header .= "Connection: close\\r\\n";
    $fp = @fsockopen($domain, 80, $errno, $errstr, 30);
    fputs($fp, $header.$param);
    $html = '';
    while (!feof($fp)) {
        $html.=fgets($fp);
    }
    echo $html;
    fclose($fp);
    

    建议继续学习:

    1. 关于IO的同步,异步,阻塞,非阻塞    (阅读:14482)
    2. 配合jquery实现异步加载页面元素    (阅读:5375)
    3. 使用django+celery+RabbitMQ实现异步执行    (阅读:5017)
    4. 异步编程与响应式框架    (阅读:3911)
    5. 多核与异步并行    (阅读:3892)
    6. redis源代码分析 - event library    (阅读:3175)
    7. Google Analytics 异步代码详解    (阅读:3163)
    8. 异步完成后新开窗口    (阅读:2951)
    9. php的异步http请求类    (阅读:2919)
    10. Script 元素的异步加载属性    (阅读:2472)
    QQ技术交流群:445447336,欢迎加入!
    扫一扫订阅我的微信号:IT技术博客大学习
    © 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

    京ICP备15002552号-1