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

时间:2014-04-29 08:25:02

标签: c# sockets tcpclient

我目前正在开发SNMP打印机监控软件的自动发现功能。我需要一个帮助方法,它从多个线程执行,每个线程检查一个范围内的ip,以确定某个IP地址的设备是否响应端口9100,以确定它实际上是一个打印机,然后再发送一个对它的SNMP请求。

我最终得到了以下方法,但是我不知道这是否是正确的方法,并且如果按照惯例正确使用此上下文中的Close()方法(我可以看到Dispose(),Disconnect ()和Shutdown()方法也可用,所以使用哪些?)。此外,我需要设置超时值max。 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;
        }

设置超时属性无效。

2 个答案:

答案 0 :(得分:1)

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

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

Socket类具有ReceiveTimeout和SendTimeout属性。

答案 1 :(得分:1)

没有必要为此使用多线程。您正在占用最终将等待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使用计时器,不是真的必要),但它易于编写,理解和使用,并且不会不必要地浪费线程。 / p>

电话会是这样的:

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。