【问题标题】:TCP connect by using socket return false resultsTCP使用套接字连接返回错误结果
【发布时间】:2013-12-20 01:01:00
【问题描述】:

这是我用来扫描端口是否打开的代码。

https://stackoverflow.com/a/8957053/2203703

有人可以尝试修复它吗?它似乎无法正常工作,即使端口关闭,代码总是返回“成功连接”

这是我用 80 端口测试过的 ip 列表

79.142.126.3 //Connection refused 
222.165.195.103 //Connection refused
64.75.193.162 //Connection refused
118.97.197.146 //Port is open
222.134.154.103 //Connection timed out 
173.0.59.170 //Port is open

这是输出:

5 sockets connected successfully
79.142.126.3 connected successfully
222.165.195.103 connected successfully
64.75.193.162 connected successfully
118.97.197.146 connected successfully
173.0.59.170 connected successfully

代码看起来不错,但我真的找不到问题。

有什么帮助吗?

【问题讨论】:

  • 出于好奇,您为什么不使用其他答案之一(例如获得 29 票和赏金的答案)?
  • curl 很好,但是 socket 也很好,速度很快,对我来说是最好的选择。

标签: php sockets tcp


【解决方案1】:

您链接的代码是很久以前编写的,当时我对非阻塞 I/O 的许多方面了解有限。

这确实需要一个事件循环,其中有很多实现,但对于这个示例,我将使用@rdlowreyAlert 库,因为它是一个极简代码,应该相当容易理解。您也可以在React 处进行循环,这是更高级别并提供更多功能。

请注意,以下示例需要 PHP 5.4+

<?php

// Array of addresses to test
$addresses = [
    '192.168.5.150',
    '192.168.5.152',
    'google.com',    // Important note: DNS is resolved synchronously here.
    '192.168.5.155', // this can seriously slow down the process as it can block
    '192.168.5.20',  // for a few seconds, async DNS resolution is non-trivial
    '192.168.40.40', // though
];
// The TCP port to test
$port = 80;
// The length of time in seconds to allow host to respond
$timeout = 5;

// This will hold the results
$lookups = [];

// Create a reactor
$reactor = (new \Alert\ReactorFactory)->select();

$count = count($addresses);
$completedCount = 0;

$onComplete = function($address, $result)
                  use(&$lookups, &$completedCount, $count, $reactor) {

    // Cancel the watchers for this address
    $reactor->cancel($lookups[$address]['failWatcher']);
    $reactor->cancel($lookups[$address]['writeWatcher']);
    $reactor->cancel($lookups[$address]['readWatcher']);

    // Store the result
    $lookups[$address] = $result;

    // If there's nothing left to do, stop the reactor
    if (++$completedCount == $count) {
        $reactor->stop();
    }
};

foreach ($addresses as $address) {
    // Normalise the address to lower-case, as it will be used as an array key
    $address = strtolower($address);

    if (!isset($lookups[$address])) {
        // Create a socket to connect asynchronously
        $sockAddr = "tcp://{$address}:{$port}";
        $flags = STREAM_CLIENT_ASYNC_CONNECT;
        $socket = stream_socket_client($sockAddr, $errNo, $errStr, 0, $flags);
        stream_set_blocking($socket, 0);

        // Set up a timeout to watch for failed connections
        $failWatcher = function() use($address, $onComplete, $timeout) {
            echo "{$address} connect failed: Connect timed out\n";
            $onComplete($address, false);
        };
        $failWatcherId = $reactor->once($failWatcher, $timeout);

        // Watch for the stream becoming writable (connection success)
        $writeWatcher = function() use($address, $onComplete) {
            echo "{$address} connected successfully\n";
            $onComplete($address, true);
        };
        $writeWatcherId = $reactor->onWritable($socket, $writeWatcher);

        // Watch for the stream becoming readable (success or explicit fail)
        $readWatcher = function() use($address, $onComplete, $socket) {
            if ('' === $data = fread($socket, 1024)) {
                echo "{$address} connect failed: Server refused connection\n";
                $onComplete($address, false);
            } else if ($data === false) {
                echo "{$address} connect failed: Stream read error\n";
                $onComplete($address, false);
            } else {
                echo "{$address} connected successfully\n";
                $onComplete($address, true);
            }
        };
        $readWatcherId = $reactor->onReadable($socket, $readWatcher);

        // Store the watcher IDs so they can be destroyed later
        $lookups[$address] = [
            'failWatcher'  => $failWatcherId,
            'writeWatcher' => $writeWatcherId,
            'readWatcher'  => $readWatcherId,
        ];
    }
}

// Set everything going
$reactor->run();

// $lookups is now an array of booleans indicating whether the address resulted
// in a successful connection

【讨论】:

    【解决方案2】:

    无论如何,这段代码都会打印出“成功”,失败时也是如此..

    可以看到echo "$count sockets connected successfully\n"echo "$address connected successfully\n"不依赖任何条件...

    只有echo "Created socket for $address\n"视情况而定,但端口关闭时也可以创建socket。

    我看不出有什么问题。将打印一般消息“X sockets connected successfully”(您可以将其删除...),但不会打印特定消息“XXXXX connected successfully”!

    【讨论】:

    • @user2203703 当你只输入一个 IP 地址(在$addresses 数组中)(并且此 IP 的 80 端口已关闭)时,请告诉我确切的输出。
    • 我照原样复制了代码,我的输出是2 sockets connected successfully 118.97.197.146 connected successfully 173.0.59.170 connected successfully。你确定没有改php代码吗?
    【解决方案3】:

    如果您负担得起按顺序测试 ips(显然,比并行测试要慢),那么您可以简化代码并从 socket_connect 函数获得有用的响应:

    <?php
    
      // An array of hosts to check
      $addresses = array(
        '79.142.126.3', //Connection refused
        '222.165.195.103', //Connection refused
        '64.75.193.162', //Connection refused
        '118.97.197.146', //Port is open
        '222.134.154.103', //Connection timed out
        '173.0.59.170' //Port is open
      );
    
      // The TCP port to test
      $testport = 80;
      // The length of time in seconds to allow host to respond
      $timeout = 5;
    
      foreach ($addresses as $address) {
    
        if (!$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) {
          echo "Could not create socket for $address\n";
          continue;
        }
    
        socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $timeout, 'usec' => 0));
        socket_set_option($sock, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $timeout, 'usec' => 0));
    
        if (@socket_connect($sock, $address, $testport)) {
            echo "$address connected successfully\n";
        }
        else {
            echo "Unable to connect to $address\n";
        }
      }
    

    回复:

    Unable to conenct to 79.142.126.3
    Unable to conenct to 222.165.195.103
    Unable to conenct to 64.75.193.162
    118.97.197.146 connected successfully
    Unable to conenct to 222.134.154.103
    173.0.59.170 connected successfully
    

    【讨论】:

      猜你喜欢
      • 2013-06-29
      • 2012-03-26
      • 2011-08-31
      • 2023-03-21
      • 2019-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多