2

我正在尝试使用 fsockopen() 检查 Selenium 服务器是否正在运行。当服务器运行时,应该设置常量。当它不是常量时,不设置。这是使用以下代码完成的:

if(!defined('TEST_SELENIUM')){
    $fp = @fsockopen('localhost', 4444);
    if ($fp !== false) {
        define('TEST_SELENIUM', true);
        fclose($fp);
    }
}

当服务器未运行时(在 Windows 7 上)出现问题。fsockopen() 不是从找到关闭的端口返回 false,而是在尝试与端口通信时停止。当服务器运行时,它会使用 netstat 快速显示。当服务器关闭时,netstat 不会从端口 4444 返回任何内容。根据我对 fsockopen() 的理解,这应该立即返回 false。但同样,它只是在尝试与端口通信时停滞不前。我不想在这里添加超时,因为这不是应用程序中应该有任何类型的停顿的点。另外,我应该注意到这似乎在 Linux 上以我期望的方式工作。但是,它在 Windows 7 上失败了。谁能告诉我我做错了什么?非常感谢!

4

1 回答 1

3

如果不添加超时,您将无法执行此操作。这与 PHP 的实现无关——这正是 TCP 套接字连接应该如何工作的。

因为 TCP 使用确认 (ACK) 来保证数据包的传递和排序,所以当您启动 TCP 连接时,客户端会发送一个 SYN 数据包,并等待返回的 SYN/ACK 数据包。客户端将继续等待这个返回的数据包,直到它被接收到,或者客户端决定它等待的时间足够长并放弃 - 这是fsockopen()接受的超时参数。

当您运行 netstat 时,它会查看绑定到本地计算机上 TCP 堆栈的应用程序- 这意味着它能够确定端口是否正在使用,而无需尝试连接到它。结果,它能够立即报告套接字是否在使用中。

实际上,您有两种选择。

  • 提供超时。请记住,超时参数可以是浮点数(因此可以小于 1 秒),因此如果您正在检查本地计算机,则可以将其设置得非常低。只是在我的 Windows XP 机器上测试它,我发现我可以将它设置为0.001(1ms),它成功连接到正在运行的服务,并返回FALSE未绑定的端口。这 1 毫秒的超时也适用于我(诚然相对安静且完全千兆)LAN 上的其他机器。YMMV,但 5ms ( 0.005) 在高速网络中应该绰绰有余。
    例如,这行代码对我来说效果很好,并且会导致脚本最多等待 1毫秒:
define('TEST_SELENIUM', (bool) @fsockopen('localhost', 4444, $en, $es, 0.001));
  • shell_exec('netstat');并解析输出。这肯定只有在您检查本地机器时才有效,并且可能不会比 1ms 超时方法快。它也不是很便携,因为各种操作系统上的 netstat 实用程序可能会产生非常细微的不同输出——不同的列顺序、不同的分隔符等。

还值得注意的是,如果 TCP 堆栈被配置为主动拒绝发送到未绑定端口的数据包(通过返回 RST 数据包),那么fsockopen()将立即失败。这可能就是你说的原因this appears to work the way I would expect it should on Linux——你测试它的 Linux 实例就是这样配置的。可能有一些注册表设置允许您将 Windows 配置为也以这种方式运行,尽管我不知道它是什么 - SuperUser的人可以帮助您。

于 2012-08-23T13:02:16.820 回答