【问题标题】:How to get IP of all hosts in LAN?如何获取局域网内所有主机的IP?
【发布时间】:2011-05-01 20:43:52
【问题描述】:

我需要列出局域网中所有已连接主机的 IP 地址。 最简单的方法是什么?

【问题讨论】:

  • 定义连接 - 你的意思是喜欢活跃?它们是防火墙还是可以被 ping 通?
  • 是的,有效。它们可以被防火墙但不一定 - 我不知道,因为我是用户而不是管理员。
  • 这是什么环境?您是否有支持 SNMP 的托管交换机?如果是这样,您只需查询开关以查看谁处于活动状态。如果它是一个小型家用路由器,那你就不走运了。
  • @TimCoker 是对的。品脱很棒,但前提是机器配置为回复 ping。 SNMP 或许是获取真实统计数据的最佳方式。

标签: c# .net network-programming ip-address


【解决方案1】:

您必须进行 ping 扫描。 System.Net 命名空间中有一个 Ping 类。示例如下。此外,这只有在您的计算机没有运行防火墙的情况下才有可能。如果他们启用了防火墙,那么除了在您的交换机上执行 SNMP 查询之外,无法确定此信息。

System.Net.NetworkInformation.Ping p = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply rep = p.Send("192.168.1.1");
if (rep.Status == System.Net.NetworkInformation.IPStatus.Success)
{
    //host is active
}

另一个问题是确定您的网络有多大。在大多数家庭情况下,您的网络掩码将是 24 位。这意味着它设置为 255.255.255.0。如果您的网关是 192.168.1.1,这意味着您网络上的有效地址将是 192.168.1.1 到 192.168.1.254。这是一个IP Calculator 来提供帮助。您必须遍历每个地址并使用 Ping 类 ping 地址并检查 PingReply。

如果您只是寻找信息而不关心如何获取信息,您可以使用 NMap。命令如下

nmap -sP 192.168.1.0/24

编辑:

就速度而言,由于您在本地网络上,因此您可以大大缩短超时间隔,因为您的机器响应时间不应超过 100 毫秒。您还可以使用 SendAsync 并行 ping 它们。以下程序将在半秒内 ping 254 地址。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.NetworkInformation;
using System.Diagnostics;
using System.Net;
using System.Threading;
using System.Net.Sockets;

namespace ConsoleApplication1
{
    class Program
    {
        static CountdownEvent countdown;
        static int upCount = 0;
        static object lockObj = new object();
        const bool resolveNames = true;

        static void Main(string[] args)
        {
            countdown = new CountdownEvent(1);
            Stopwatch sw = new Stopwatch();
            sw.Start();
            string ipBase = "10.22.4.";
            for (int i = 1; i < 255; i++)
            {
                string ip = ipBase + i.ToString();

                Ping p = new Ping();
                p.PingCompleted += new PingCompletedEventHandler(p_PingCompleted);
                countdown.AddCount();
                p.SendAsync(ip, 100, ip);
            }
            countdown.Signal();
            countdown.Wait();
            sw.Stop();
            TimeSpan span = new TimeSpan(sw.ElapsedTicks);
            Console.WriteLine("Took {0} milliseconds. {1} hosts active.", sw.ElapsedMilliseconds, upCount);
            Console.ReadLine();
        }

        static void p_PingCompleted(object sender, PingCompletedEventArgs e)
        {
            string ip = (string)e.UserState;
            if (e.Reply != null && e.Reply.Status == IPStatus.Success)
            {
                if (resolveNames)
                {
                    string name;
                    try
                    {
                        IPHostEntry hostEntry = Dns.GetHostEntry(ip);
                        name = hostEntry.HostName;
                    }
                    catch (SocketException ex)
                    {
                        name = "?";
                    }
                    Console.WriteLine("{0} ({1}) is up: ({2} ms)", ip, name, e.Reply.RoundtripTime);
                }
                else
                {
                    Console.WriteLine("{0} is up: ({1} ms)", ip, e.Reply.RoundtripTime);
                }
                lock(lockObj)
                {
                    upCount++;
                }
            }
            else if (e.Reply == null)
            {
                Console.WriteLine("Pinging {0} failed. (Null Reply object?)", ip);
            }
            countdown.Signal();
        }
    }
}

编辑:在我自己使用了一些之后,我修改了程序以输出有多少 IP 响应的计数。有一个 const 布尔值,如果设置为 true,将导致程序解析 IP 的主机名。但是,这会显着减慢扫描速度。 (不到半秒到16秒)还发现如果IP地址指定错误(自己打错了),回复对象可以为空,所以我处理了。

【讨论】:

  • @Tim,你知道 Nmap 有没有 API 吗?
  • 请注意,RFC1918 表示这些范围都对 LAN 有效:10.0.0.0 – 10.255.255.255、172.16.0.0 – 172.31.255.255、192.168.0.0 – 192.168.255.255
  • @Brad,不确定是否有完整的 API,但它是按照常规 UNIX 程序的精神设计的,因此您可以通过命令行轻松执行它并捕获标准输出。有一些选项可以格式化 via XML 以及 GREPable 格式(IE,与正则表达式一起使用)。有关如何在 c# 中执行命令和捕获输出的信息,请参阅此答案。 stackoverflow.com/questions/3258704/…
  • 多个独立的 IP 子网没有理由共享同一个物理 LAN,因此这种过程是有限的(并且不会区分由交换机链接的 LAN)。那是在考虑 VLAN 之前。 Q的真正答案是“一般来说没有这样的方法”。在实践中,除非其他节点不响应 ping,否则在不访问网关的情况下 ping 每个可访问的地址(即 this-IP & mask == other-IP & mask 的地方)都会起作用。
  • 其惊人的代码,更多的艺术。根据我的偏好做了一些细微的改变,现在它像 Strom 一样运行。
【解决方案2】:

您需要建立一个地址范围(例如 192.168.0.1 - 192.168.255.254)并 ping 每个地址。如果收到响应,则该主机处于活动状态。

异步 ​​Ping 教程:

http://www.geekpedia.com/tutorial234_Asynchronous-Ping-using-Csharp.html

但是,一些较新的操作系统会阻止 ping 请求 (ICMP)。这需要在每台计算机的防火墙中禁用,您才能收到响应。

【讨论】:

    【解决方案3】:

    您可以 ping 地址范围并记录主机是否响应。当然,这需要主机响应 ping 数据包。

    【讨论】:

    • Ping 例如 255 台主机有点费时——我想是这样。有更快的方法吗?
    • 一秒钟并不耗时。只需同时完成所有 255 次 ping,而不是一个接一个等待超时。
    • 如何更快地做到这一点?即使我 ping 10 台主机也需要几秒钟。
    【解决方案4】:

    您可以在托管代码中完成所有操作。我使用 System.DirectoryServices 和 System.Net。基本上,我从 DirectoryServices 中获取本地计算机的名称(处理域和工作组),然后从 System.Net.Dns 中获取每个主机的 IP 地址。这里的一切都打包成一个方便的类...

    public class NetworkComputer {
        private string _domain;
        private string _name;
        private IPAddress[] _addresses = null;
    
        public string Domain { get { return _domain; } }
        public string Name { get { return _name; } }
        public IPAddress[] Addresses { get { return _addresses; } }
    
        private NetworkComputer(string domain, string name) {
            _domain = domain;
            _name = name;
            try { _addresses = Dns.GetHostAddresses(name); } catch { }
        }
    
        public static NetworkComputer[] GetLocalNetwork() {
            var list = new List<NetworkComputer>();
            using(var root = new DirectoryEntry("WinNT:")) {
                foreach(var _ in root.Children.OfType<DirectoryEntry>()) {
                    switch(_.SchemaClassName) {
                        case "Computer":
                            list.Add(new NetworkComputer("", _.Name));
                            break;
                        case "Domain":
                            list.AddRange(_.Children.OfType<DirectoryEntry>().Where(__ => (__.SchemaClassName == "Computer")).Select(__ => new NetworkComputer(_.Name, __.Name)));
                            break;
                    }
                }
            }
            return list.OrderBy(_ => _.Domain).ThenBy(_ => _.Name).ToArray();
        }
    }
    

    然后只需调用静态方法来获取您的 LAN 计算机的数组...

    var localComputers = NetworkComputer.GetLocalNetwork();
    

    【讨论】:

      【解决方案5】:

      您可以(我真的不太清楚!)使用 NetBIOS(以某种方式请求 netbios 命名表?)http://technet.microsoft.com/en-us/library/cc757216%28WS.10%29.aspx,而不是安排一个疯狂的 ping 派对。或者为什么不询问您的 DHCP 服务器?

      【讨论】:

      • DHCP 服务器不太可能返回 ACTIVE。您只知道最近处于活动状态 - 仍然需要 ping 并且您可能会错过一些静态配置的内容。
      • 是的,唯一可以确定的方法是搜索您的网络交换机,然后按照所有电缆..
      【解决方案6】:
      namespace WindowsFormsApplication1
      {
          class WifiInformation
          {
              static CountdownEvent countdown;
              static int upCount = 0;
              static object lockObj = new object();
              const bool resolveNames = true;
      
              static void Main(string[] args)
              {
                  string ipBase = getIPAddress();
                  string[] ipParts = ipBase.Split('.');
                  ipBase = ipParts[0] + "." + ipParts[1] + "." + ipParts[2] + ".";
                  for (int i = 1; i < 255; i++)
                  {
                      string ip = ipBase + i.ToString();
      
                      Ping p = new Ping();
                      p.PingCompleted += new PingCompletedEventHandler(p_PingCompleted);
                      p.SendAsync(ip, 100, ip);
                  }
                  Console.ReadLine();
              }
      
              static void p_PingCompleted(object sender, PingCompletedEventArgs e)
              {
                  string ip = (string)e.UserState;
                  if (e.Reply != null && e.Reply.Status == IPStatus.Success)
                  {
                      if (resolveNames)
                      {
                          string name;
                          try
                          {
                              IPHostEntry hostEntry = Dns.GetHostEntry(ip);
                              name = hostEntry.HostName;
                          }
                          catch (SocketException ex)
                          {
                              name = "?";
                          }
                          Console.WriteLine("{0} ({1}) is up: ({2} ms)", ip, name, e.Reply.RoundtripTime);
                      }
                      else
                      {
                          Console.WriteLine("{0} is up: ({1} ms)", ip, e.Reply.RoundtripTime);
                      }
                      lock (lockObj)
                      {
                          upCount++;
                      }
                  }
                  else if (e.Reply == null)
                  {
                      Console.WriteLine("Pinging {0} failed. (Null Reply object?)", ip);
                  }
              }
      
              public static string getIPAddress()
              {
                  IPHostEntry host;
                  string localIP = "";
                  host = Dns.GetHostEntry(Dns.GetHostName());
                  foreach (IPAddress ip in host.AddressList)
                  {
                      if (ip.AddressFamily == AddressFamily.InterNetwork)
                      {
                          localIP = ip.ToString();
                      }
                  }
                  return localIP;
              }
          }
      }
      

      【讨论】:

        【解决方案7】:

        Ping 到全球广播 ip 地址 (192.168.1.255)

        通常我们会收到所有连接到 LAN 的主机的回复。或者,如果您有任何特定的 LAN 网络,请 ping 到该网络的广播 ID(即该范围内的最后一个 IP 地址)。

        那么你就可以知道所有连接到局域网中的主机的ip地址了。

        【讨论】:

        • 什么?真的吗?
        • 当我们将集线器用于以太网时,这曾经可以恢复,(全部?)交换机只是忽略 IP 广播并且不将这些消息中继到所有端口。
        猜你喜欢
        • 2016-02-26
        • 1970-01-01
        • 2012-11-27
        • 1970-01-01
        • 2011-07-21
        • 1970-01-01
        • 1970-01-01
        • 2011-12-02
        • 2013-07-03
        相关资源
        最近更新 更多