IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

fsockopen 异步处理

生活在別處 2012-05-17 23:28:23 累计浏览 10,288 次
本机暂存

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

    因为之前采用异步处理时 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. Vibe新开源项目 - Vaala AI Gateway (2026-05-17 02:10:19)
    2. SmartPerfetto 架构文章 Q&A:8 个深度技术问答 (2026-04-10 11:00:00)
    3. 让 AI 把我的 PHP 博客重写成 Go (2026-03-27 18:33:54)

    查看更多 后端 文章 →

    建议继续学习

    1. 配置Nginx+uwsgi更方便地部署python应用 (累计阅读 107,012)
    2. 搜狐闪电邮箱的 Nginx/Postfix 使用模式 (累计阅读 33,833)
    3. 记录一个软中断问题 (累计阅读 16,898)
    4. 解析nginx负载均衡 (累计阅读 16,527)
    5. server日志的路径分析 (累计阅读 11,193)
    6. Nginx模块开发入门 (累计阅读 11,110)
    7. 检查nginx配置,重载配置以及重启的方法 (累计阅读 10,803)
    8. Cacti 添加 Nginx 监控 (累计阅读 10,553)
    9. 使用Squid缓存视频 (累计阅读 10,285)
    10. Nginx+FastCgi+Php 的工作机制 (累计阅读 10,146)