【问题标题】:PHP fsockopen connect timeout via browser but not via CLIPHP fsockopen 通过浏览器而不是通过 CLI 连接超时
【发布时间】:2014-04-13 10:45:11
【问题描述】:

我正在解决一个奇怪的问题并且没有想法,希望这里有人可以帮助我。这是关于与外部服务器的随机连接超时 - 从浏览器运行时非常频繁,但从 CLI 运行时非常罕见。更多细节和代码:

在我的网站example.com 我有一个表格。一旦用户提交它(HTTP POST),php 就会向外部服务器 http://external.com/check.php 发送一个请求(另一个 POST),其中包含一些 POST 数据。一旦得到响应,它将继续执行其余代码并最终输出一个网页。它看起来像这样:

if (!empty($_POST) {
    // here goes some POST validation stuff, and then:
    req = http_build_query($_POST);
    $http_request = "POST /check.php HTTP/1.0\r\n";
    $http_request .= "Host: external.com\r\n";
    $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
    $http_request .= "Content-Length: " . strlen($req) . "\r\n";
    $http_request .= "User-Agent: SpeciallyDefinedForExternal.com/PHP\r\n";
    $http_request .= "\r\n";
    $http_request .= $req;
}

if (false == ($fs = fsockopen($host, $port, $errno, $errstr, 10))) {
    throw new Exception($errstr, $errno);
}

fwrite($fs, $http_request);
while (!feof($fs)) {
    $response .= fgets($fs, 1024); // One TCP-IP packet
}
fclose($fs);

// do some stuff depending on on $response

当我在开发服务器上运行它时一切正常,但是一旦我将它部署到生产环境中,它会随机不断地在fsockopen() 调用时抛出异常。

我在日志文件中检查了大约 15% 的 fsockopen() 调用成功,其余为 110 Connection timed out 错误。

最奇怪的是,当我登录到生产服务器并通过 CLI 运行相同的 sn-p 代码时,只有 0.1% 的请求会遇到连接超时错误,而 99.9% 的请求可以完美运行! 即使我输入了 2000 次迭代的循环,比率也保持不变。

我与external.com 的管理员交谈,他们说他们只有 5% 的服务器负载,而他们的其他客户没有遇到任何超时问题,所以看起来这是我的 php 或网络问题。

我的开发服务器和生产服务器的配置是相同的,唯一的区别是负载 - 生产中每秒大约 150 个请求。需要说明的是:这 150 个请求是我的访问用户,但并不是每个请求都提交表单并打开套接字。每秒只有大约 14 个这样的用户,即每秒大约有 14 个 POST 从我的服务器发送到 external.com

当我尝试用curl 替换fsockopen() 时,它变得更好了——现在发送到external.com 的帖子中有大约45% 是成功的(通过浏览器)——这仍然不能令人满意。当我从 CLI 运行时 - 它运行良好。并且错误信息略有不同,但含义实际上相同:couldn't connect to host

任何想法可能是什么原因,通过浏览器的请求往往会失败,而通过 CLI 发送的请求却可以正常工作?

如果重要的话:我使用的是 php 5.3.27,而我的网络服务器是 Apache。当我通过浏览器调用phpinfo() 和通过CLI 调用php -v 时,版本号是相同的。

提前致谢,

Pstryk

* 编辑 *

原来是他们的路由器配置有问题。

external.com 的管理员没有看到任何负载增加,因为他们正在查看错误的机器。罪魁祸首是他们的路由器,而不是服务器external.com。 他们已经更改了路由器配置中的某些内容,但不要透露它到底是什么设置,我想我们永远不会发现。有趣的是,既然他们已经解决了这个问题,现在我的开发服务器上出现了同样的问题......但这是我可以忍受的。需要明确的是:在我这边,开发服务器使用与生产服务器不同的路由器,但它们的配置是相同的(IP 等除外)。 我要感谢所有试图帮助我解决这个问题的人。显然我们无能为力。

【问题讨论】:

  • 你的服务器是linux还是windows?它是共享主机还是分配带宽的专用服务器?
  • 它是基于 linux 的,托管在我公司自己的数据中心。 Bandwitdh 非常广泛,external.com 返回的数据大小小于 100 个字符(加上 HTTP 标头)
  • 您说的是每秒 150 个请求。这是每分钟 9000 个请求。在不到 7 分钟的时间内,您使用了所有服务器套接字。您应该针对这种负载调整您的 linux 系统。此外,考虑保持活动连接和一个小守护进程来处理这种流量,这种实现会浪费大量网络资源。
  • 抱歉,我可能不够清楚:我的服务器(example.com)每秒大约有 150 个请求,但并非每个访问用户都提交表单并打开套接字。我的服务器每秒向 external.com 发出的请求只有大约 14 个。我将编辑原始问题以明确这一点。
  • 尝试将 CURL 超时时间提高到 60 秒,看看会发生什么。 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,60); curl_setopt($ch, CURLOPT_TIMEOUT, 60);

标签: php curl fsockopen connection-timeout command-line-interface


【解决方案1】:

也许您已经检查过了,但是 php-cli、mod_php(dev、stage、live)的配置真的相同吗?似乎配置了一个非常短的超时。这也可以解释 fsockopen 和 curl 的不同行为,它们具有不同的设置 iirc。

请看:http://php.net/stream_set_timeout 在 fsockopen 的文档中注意到超时仅用于打开套接字。

【讨论】:

  • 是的,所有这些配置文件都是相同的(除了必须不同的东西)。 php.net/stream_set_timeout 中的第一个示例显示我需要为已经打开的连接设置超时,但在我的情况下,连接由于超时而无法打开;)换句话说 - 它无法建立连接我可以设置一个超时。
猜你喜欢
  • 1970-01-01
  • 2012-09-07
  • 1970-01-01
  • 1970-01-01
  • 2014-08-20
  • 2014-05-25
  • 1970-01-01
  • 1970-01-01
  • 2011-10-30
相关资源
最近更新 更多