C#获取局域网所有IP几个方法总结

获得局域网IP的基本原理如下:

1.一个局域网中的IP网段是固定的,如192.168.1.xxx,也即搜索出来的IP的第四个字节分布于0-255之间,所以几乎所有获取方法都是基于IP遍历。在代码中就是一个循环。

2.在遍历过程中需要考虑两个问题:(1)如何判断当前局域网中是否有某个IP的计算机  (2)如何获取IP的前三个字节

3.第二个问题容易解决,首先获取本地计算机的IP,截取前三个字节就可以获得。

4.第一个问题有好多种判断方法,因此也就有了好多种获取局域网IP的方法。我只测试过两种方法,(1)Ping方法 (2)类似arp枚举方式 。  还有其他博客也提到了一方法,具体可以见文末链接。接下来介绍两种方法,并附上代码。

方法一 Ping方法

Ping方法分为两种,同步方式和异步方式。经测试,均可以获得局域网所有IP(所有是指配置正确的电脑,后边会解释同一局域网下不同电脑搜索到的IP不一样的原因),只是速度上有所区别,同步方式的时间基本为 每一次Ping的时间×遍历个数,异步方式的时间基本为一到两倍的单次Ping时间,即2-3秒左右。

(1)同步Ping

public void getIP()
        {

            //获取本地机器名 
            string _myHostName = Dns.GetHostName();
            //获取本机IP 
            string _myHostIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault<IPAddress>(a => a.AddressFamily.ToString().Equals("InterNetwork")).ToString();
            //MessageBox.Show(_myHostIP);
            //截取IP网段
            string ipDuan = _myHostIP.Remove(_myHostIP.LastIndexOf('.'));
            //MessageBox.Show(ipDuan);
            //枚举网段计算机
            Ping myPing = new Ping();
            string data = "";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            for (int i = 1; i <= 255; i++)
            {  
                string pingIP = ipDuan + "." + i.ToString();
                PingReply pingReply = myPing.Send(pingIP,120,buffer);
                if (pingReply.Status == IPStatus.Success)
                {
                    ipList.Add(pingIP);
                    label3.Text = "答复的主机地址:" + pingReply.Address.ToString() + "\n";
                    label3.Text += "往返时间:" + pingReply.RoundtripTime.ToString() + "\n";
                    label3.Text += "生存时间:" + pingReply.Options.Ttl.ToString() + "\n";
                    label3.Text += "是否控制数据包的分段:" + pingReply.Options.DontFragment.ToString() + "\n";
                    label3.Text += "缓冲区大小:" + pingReply.Buffer.Length.ToString() + "\n";
                    label3.Refresh();
                }
                else
                {
                    label3.Text = pingIP + "不在线";
                    label3.Refresh();
                }
                    
            }
        }
源码中标注的三行是核心代码,即创建Ping对象,发送Ping消息,检查返回值是否成功。其他是我自己工程涉及到的东西,如果要使用改代码需自己修改。至于这几个函数怎么用自行百度。

(2)异步Ping

private void EnumComputers()  
        {  
             try  
             {  
               for (int i = 1; i <= 255; i++)  
               {  
                 Ping myPing;  
                 myPing = new Ping();  
                 myPing.PingCompleted += new PingCompletedEventHandler(_myPing_PingCompleted);  
  
                 string pingIP = "192.168.1." + i.ToString();  
                 myPing.SendAsync(pingIP, 2000, null);  
               }  
             }  
             catch  
             {
                 ;
             }  
        }  
  
        private void _myPing_PingCompleted(object sender, PingCompletedEventArgs e)  
        {  
              if (e.Reply.Status == IPStatus.Success)  
              {
                  ipList.Add(e.Reply.Address.ToString());
              }

              count++;
              
              if (count >= 255)
              {
                  Thread t1 = new Thread(new ParameterizedThreadStart(TestMethod));
                  t1.IsBackground = true;
                  t1.Start(this);

                  
              }
        }

基本思路为,首先创建Ping对象,创建Ping完成时的事件响应变量,并将响应函数绑定,然后开始异步Ping操作;在响应函数中,检测Ping响应是否成功,如果成功,则加入列表,当256个IP都Ping完之后,开启一个新的线程,用来进行后续处理。


方法二 类arp方法

这个方法我也不太懂,测试了一下找到的代码是可以用的。但这个方法存在问题,arp方法是在存于本地电脑中的IP列表进行查询,也即计算机之前就已经有一个局域网当前IP的表格了,直接查表就行。但是我也不清楚它这个表是什么时候更新的,经常出现的结果就是一会能搜索出这几个IP,一会儿搜出那几个,一会儿都没有了。个人认为是方法本身存在的问题。可以在cmd中用arp -a命令来测试,会发现有的电脑就是搜不到。原理不是很懂,只贴下代码。

        [StructLayout(LayoutKind.Sequential)]
        struct MIB_IPNETROW
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwIndex;
            [MarshalAs(UnmanagedType.U4)]
            public int dwPhysAddrLen;
            [MarshalAs(UnmanagedType.U1)]
            public byte mac0;
            [MarshalAs(UnmanagedType.U1)]
            public byte mac1;
            [MarshalAs(UnmanagedType.U1)]
            public byte mac2;
            [MarshalAs(UnmanagedType.U1)]
            public byte mac3;
            [MarshalAs(UnmanagedType.U1)]
            public byte mac4;
            [MarshalAs(UnmanagedType.U1)]
            public byte mac5;
            [MarshalAs(UnmanagedType.U1)]
            public byte mac6;
            [MarshalAs(UnmanagedType.U1)]
            public byte mac7;
            [MarshalAs(UnmanagedType.U4)]
            public int dwAddr;
            [MarshalAs(UnmanagedType.U4)]
            public int dwType;
        }

        /// <summary>
        /// GetIpNetTable external method
        /// </summary>
        /// <param name="pIpNetTable"></param>
        /// <param name="pdwSize"></param>
        /// <param name="bOrder"></param>
        /// <returns></returns>
        [DllImport("IpHlpApi.dll")]
        [return: MarshalAs(UnmanagedType.U4)]
        static extern int GetIpNetTable(IntPtr pIpNetTable,
                                        [MarshalAs(UnmanagedType.U4)] ref int pdwSize, bool bOrder);

        /// <summary>
        /// Error codes GetIpNetTable returns that we recognise
        /// </summary>
        const int ERROR_INSUFFICIENT_BUFFER = 122;
        /// <summary>
        /// Get the IP and MAC addresses of all known devices on the LAN
        /// </summary>
        /// <remarks>
        /// 1) This table is not updated often - it can take some human-scale time
        ///    to notice that a device has dropped off the network, or a new device
        ///    has connected.
        /// 2) This discards non-local devices if they are found - these are multicast
        ///    and can be discarded by IP address range.
        /// </remarks>
        /// <returns></returns>
        private static Dictionary<IPAddress, PhysicalAddress> GetAllDevicesOnLAN()
        {
            Dictionary<IPAddress, PhysicalAddress> all = new Dictionary<IPAddress, PhysicalAddress>();
            // Add this PC to the list...
            all.Add(GetIPAddress(), GetMacAddress());
            int spaceForNetTable = 0;
            // Get the space needed
            // We do that by requesting the table, but not giving any space at all.
            // The return value will tell us how much we actually need.
            GetIpNetTable(IntPtr.Zero, ref spaceForNetTable, false);
            // Allocate the space
            // We use a try-finally block to ensure release.
            IntPtr rawTable = IntPtr.Zero;
            try
            {
                rawTable = Marshal.AllocCoTaskMem(spaceForNetTable);
                // Get the actual data
                int errorCode = GetIpNetTable(rawTable, ref spaceForNetTable, false);
                if (errorCode != 0)
                {
                    // Failed for some reason - can do no more here.
                    throw new Exception(string.Format(
                        "Unable to retrieve network table. Error code {0}", errorCode));
                }
                // Get the rows count
                int rowsCount = Marshal.ReadInt32(rawTable);
                IntPtr currentBuffer = new IntPtr(rawTable.ToInt64() + Marshal.SizeOf(typeof(Int32)));
                // Convert the raw table to individual entries
                MIB_IPNETROW[] rows = new MIB_IPNETROW[rowsCount];
                for (int index = 0; index < rowsCount; index++)
                {
                    rows[index] = (MIB_IPNETROW)Marshal.PtrToStructure(new IntPtr(currentBuffer.ToInt64() +
                                                                                  (index * Marshal.SizeOf(typeof(MIB_IPNETROW)))
                                                                                 ),
                                                                       typeof(MIB_IPNETROW));
                }
                // Define the dummy entries list (we can discard these)
                PhysicalAddress virtualMAC = new PhysicalAddress(new byte[] { 0, 0, 0, 0, 0, 0 });
                PhysicalAddress broadcastMAC = new PhysicalAddress(new byte[] { 255, 255, 255, 255, 255, 255 });
                foreach (MIB_IPNETROW row in rows)
                {
                    IPAddress ip = new IPAddress(BitConverter.GetBytes(row.dwAddr));
                    byte[] rawMAC = new byte[] { row.mac0, row.mac1, row.mac2, row.mac3, row.mac4, row.mac5 };
                    PhysicalAddress pa = new PhysicalAddress(rawMAC);
                    if (!pa.Equals(virtualMAC) && !pa.Equals(broadcastMAC) && !IsMulticast(ip))
                    {
                        //Console.WriteLine("IP: {0}\t\tMAC: {1}", ip.ToString(), pa.ToString());
                        if (!all.ContainsKey(ip))
                        {
                            all.Add(ip, pa);
                        }
                    }
                }
            }
            finally
            {
                // Release the memory.
                Marshal.FreeCoTaskMem(rawTable);
            }
            return all;
        }

        /// <summary>
        /// Gets the IP address of the current PC
        /// </summary>
        /// <returns></returns>
        private static IPAddress GetIPAddress()
        {
            String strHostName = Dns.GetHostName();
            IPHostEntry ipEntry = Dns.GetHostEntry(strHostName);
            IPAddress[] addr = ipEntry.AddressList;
            foreach (IPAddress ip in addr)
            {
                if (!ip.IsIPv6LinkLocal)
                {
                    return (ip);
                }
            }
            return addr.Length > 0 ? addr[0] : null;
        }

        /// <summary>
        /// Gets the MAC address of the current PC.
        /// </summary>
        /// <returns></returns>
        private static PhysicalAddress GetMacAddress()
        {
            foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
            {
                // Only consider Ethernet network interfaces
                if (nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet &&
                    nic.OperationalStatus == OperationalStatus.Up)
                {
                    return nic.GetPhysicalAddress();
                }
            }
            return null;
        }

        /// <summary>
        /// Returns true if the specified IP address is a multicast address
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        private static bool IsMulticast(IPAddress ip)
        {
            bool result = true;
            if (!ip.IsIPv6Multicast)
            {
                byte highIP = ip.GetAddressBytes()[0];
                if (highIP < 224 || highIP > 239)
                {
                    result = false;
                }
            }
            return result;
        }
    }
直接复制到工程中就可以用,最后的IP列表存在all中。


另外在研究的过程中还发现了一个问题以及相应的解决方法:

问题:同一个局域网中的两台电脑,搜索出来的结果不一致,经常表现为互相搜不到。

解决方法:右键 “打开网络和共享中心”,点击“更改高级共享设置”,设置为“启用网络发现”,“启用文件和打印机共享”,就可以了。


这里是一些相关方法的链接

1 .http://blog.csdn.net/zengjice/article/details/8715748

2. http://blog.csdn.net/panyanyan/article/details/6585669


现在又在看如何能设置超时连接。就是我搜到列表之后,开始一个一个连接,看看他们有没有启动服务器,如果局域网中没有服务器,那么本机建立服务器;如果局域网中能成功连接到服务器,那么本机作为客户端。这样就能实现局域网中永远只有一个服务器,其他都是客户端。而且不需要固定的服务器。

但现在的问题是每次尝试连接服务器时,都要花好长时间,将近10-20秒不等,遍历下来之后感觉时间好长,所以看看如何能设置连接超时,或者有什么异步方法;我尝试了一个异步方法,但是没有成功。继续研究。


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值