检查IP地址和端口是否有响应

本文关键字:是否 响应 IP 地址 检查 | 更新日期: 2023-09-27 18:00:36

我目前正在为SNMP打印机监视器软件开发一个自动发现功能。我需要一个助手方法,它由几个线程执行,每个线程检查一个范围内的ip,以确定某个ip地址的设备是否响应端口9100,并在向其发送SNMP请求之前确定它实际上是一台打印机

我最终得到了以下方法,但我不知道这是否是正确的方法,也不知道按照惯例,在这种情况下Close()方法的使用是否正确(我可以看到Dispose()、Disconnect()和Shutdown()方法也可用,那么该用哪种方法呢?)。此外,我需要设置一个最长5秒的超时值,这样线程在显示结果之前不会停留太久。到目前为止我的代码:

private bool GetTCPPrinterResponse(IPAddress _ip)
{
        int port = 9100;
        bool isResponsive = false;
        Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        try
        {
            s.Connect(_ip, port);
            isResponsive = true;
        }
        catch (SocketException)
        {
            isResponsive = false;
        }
        finally
        {
            s.Close();
        }
        return isResponsive;
    }

方法编辑后:

private bool GetTCPPrinterResponse(IPAddress _ip)
        {
            int port = 9100;
            bool isResponsive = false;
            using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                s.ReceiveTimeout = 3000;
                s.SendTimeout = 3000;
                try
                {
                    s.Connect(_ip, port);
                    isResponsive = true;
                }
                catch (SocketException)
                {
                    isResponsive = false;
                }
            }
            return isResponsive;
        }

设置Timeout属性无效。

检查IP地址和端口是否有响应

这是检查计算机/打印机是否在某个端口的某个IP上联机的正确方法。您应该调用dispose方法来释放对象正在使用的内存。Socket类实现IDisposable,因此最好使用using,而不用担心调用dispose,因为using会为您执行此操作。

using(Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
//...
}

套接字类具有属性ReceiveTimeout和SendTimeout。

没有必要为此使用多线程。您正在占用线程,这些线程最终将等待I/O操作完成。相反,为什么不使用异步I/O呢?

public async Task<Tuple<IPAddress, bool>> GetResponse(IPAddress address)
{
  using (var client = new TcpClient(AddressFamily.InterNetwork))
  {
    var connectTask = client.ConnectAsync(address, 80);
    await Task.WhenAny(connectTask, Task.Delay(5000));
    if (connectTask.IsCompleted)
        return Tuple.Create(address, true);
    else
        return Tuple.Create(address, false);
  }
}

这一点可以进一步改进——超时机制有点浪费(Task.Delay使用定时器,不是真正必要的),但它很容易编写、理解和使用,而且不会不必要地浪费线程。

然后电话会是这样的:

Task<Tuple<IPAddress, bool>>[] tasks = 
    new []
    {
      GetResponse(Dns.GetHostAddresses("www.google.com").First()),
      GetResponse(Dns.GetHostAddresses("www.microsoft.com").First()),
      GetResponse(Dns.GetHostAddresses("www.yahoo.com").First()),
      GetResponse(Dns.GetHostAddresses("www.altavista.com").First()),
    };
Task.WhenAll(tasks).Wait();
foreach (var t in tasks)
    t.Result.Dump(); // t.Result has the IP address and status

这将等待所有设备做出响应(或超时)。当然,没有什么可以阻止你以一种更具交互性的方式来做这件事——你可以在数据返回时轻松地用数据更新UI。

相关文章: