首先非常感謝Melou的http://www.cnblogs.com/luoht/archive/2009/12/18/1627431.html的隨筆,對於初學C#的我,參考你的隨筆對我的學習真是有莫大幫助。
C#遍歷局域網的幾種方法:
1、微軟社區上介紹了使用Active Directory 來遍歷局域網
首先我們來了解DirectoryEntry類是一個什么類。
命名空間: System.DirectoryServices
程序集: System.DirectoryServices(在 System.DirectoryServices.dll 中)
DirectoryEntry類可封裝Active Directory 域服務層次結構中的節點或對象。
其中有構造函數
DirectoryEntry(String),初始化 DirectoryEntry 類的新實例,該類將此實例綁定到位於指定路徑的 Active Directory 域服務中的節點。
鏈接:https://msdn.microsoft.com/zh-cn/library/system.directoryservices.directoryentry.aspx
我們必須了解其中的Active Directory
使用 Active Directory(R) 域服務 (AD DS) 服務器角色,可以創建用於用戶和資源管理的可伸縮、安全及可管理的基礎機構,並可以提供對啟用目錄的應用程序(如 Microsoft(R) Exchange Server)的支持。
AD DS 提供了一個分布式數據庫,該數據庫可以存儲和管理有關網絡資源的信息,以及啟用了目錄的應用程序中特定於應用程序的數據。運行 AD DS 的服務器稱為域控制器。管理員可以使用 AD DS 將網絡元素(如用戶、計算機和其他設備)整理到層次內嵌結構。內嵌層次結構包括 Active Directory 林、林中的域以及每個域中的組織單位 (OU)。
鏈接:https://technet.microsoft.com/zh-cn/library/hh831484.aspx
接下來看怎么利用DirectoryEntry
利用DirectoryEntry組件來查看網絡
//C# 操作WINNT本地用戶和組 DirectoryEntry DEMain = new DirectoryEntry("WinNT:"); foreach(DirectoryEntry DEGroup in DEMain.Children) { //如果和選擇的用戶組相同 if(DEGroup.Name.ToLower() == comb_workgroup.Text.ToLower()) { //讀出用戶組下的每一個主機名 foreach(DirectoryEntry DEComputer in DEGroup.Children) { //濾掉無效結果 Computer: Schema if(DEComputer.Name.ToLower() != "schema") { listb_computer.Items.Add(DEComputer.Name); } } } }
效果評價:速度慢,效率低,還有一個無效結果 Computer: Schema 使用的過程中注意慮掉。
2、利用Dns.GetHostByAddress和IPHostEntry遍歷局域網
Dns.GetHostByAddress類:返回指定主機的 Internet 協議 (IP) 地址。
命名空間: System.Net
程序集: System(在 System.dll 中)
public static IPAddress[] GetHostAddresses( string hostNameOrAddress )
IPHostEntry類:為 Internet 主機地址信息提供容器類。
命名空間: System.Net
程序集: System(在 System.dll 中)
private void EnumComputers2() { //從192.168.0.1 到 192.168.0.255開始依次嘗試 for (int i = 1; i <= 255; i++) { string scanIP = "192.168.0." + i.ToString(); IPAddress myScanIP = IPAddress.Parse(scanIP); IPHostEntry myScanHost = null; try { //獲取myScanIP的IP地址 myScanHost = Dns.GetHostByAddress(myScanIP); } catch { continue; } if (myScanHost != null) { //返回IP和主機名 Console.WriteLine(scanIP + "|" + myScanHost.HostName); } } }
System.Net.NetworkInformation.Ping類:允許應用程序確定是否可通過網絡訪問遠程計算機。
命名空間:System.Net.NetworkInformation
程序集:System(在 system.dll 中)
delegate void WT(int n); Thread t; private string GetMacAddress(string hostip)//獲取遠程IP(不能跨網段)的MAC地址 { string Mac = ""; try { Int32 ldest = inet_addr(hostip); //將IP地址從 點數格式轉換成無符號長整型 Int64 macinfo = new Int64(); Int32 len = 6; //SendARP函數發送一個地址解析協議(ARP)請求獲得指定的目的地IPv4地址相對應的物理地址 SendARP(ldest, 0, ref macinfo, ref len); string TmpMac = Convert.ToString(macinfo, 16).PadLeft(12, '0');//轉換成16進制 注意有些沒有十二位 Mac = TmpMac.Substring(0, 2).ToUpper();// for (int i = 2; i < TmpMac.Length; i = i + 2) { Mac = TmpMac.Substring(i, 2).ToUpper() + "-" + Mac; } } catch (Exception Mye) { Mac = "獲取遠程主機的MAC錯誤:" + Mye.Message; } return Mac; } private void EnumComputers(int n) { //lock (this) //Invoke(new MethodInvoker(delegate() //{ //注冊委托 if (this.txtAddrs.InvokeRequired) { WT d = new WT(EnumComputers); this.Invoke(d, new object[] { n }); } else { try { for (int i = 0; i <= 255; i++) { Ping myPing; myPing = new Ping(); //當發送 Internet 控制消息協議 (ICMP) 回送消息並接收相應 ICMP 回送答復消息的異步操作完成或被取消時發生。 myPing.PingCompleted += new PingCompletedEventHandler(myPing_PingCompleted); string pingIP = "192.168." + n.ToString() + "." + i.ToString(); //嘗試以異步方式向指定的計算機發送Internet控制消息協議(ICMP)回送消息,並從該計算機接收相應的ICMP回送答復消息。 myPing.SendAsync(pingIP, 1000, null); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } //})); } private void myPing_PingCompleted(object sender, PingCompletedEventArgs e) { StringBuilder sb = new StringBuilder(); if (e.Reply.Status == IPStatus.Success) { sb.Append("IP:" + e.Reply.Address.ToString() + "\r\n"); //獲取MAC地址 string mac = GetMacAddress(e.Reply.Address.ToString()); sb.Append("MAC:" + mac + "\r\n\r\n"); num++; } this.txtAddrs.Text += sb.ToString(); //this.lbIPs.Text = "在線IP數:" + num.ToString(); this.lbIPs.Text = num.ToString(); } private void button2_Click(object sender, EventArgs e) { this.txtAddrs.Text = ""; num = 0; t = new Thread(() => EnumComputers((int)(this.txtIP2.Value))); t.IsBackground = true; t.Start(); //EnumComputers((int)(this.txtIP2.Value)); }
需要注意的是取計算機名稱如果用Dns.GetHostByAddress取計算機名稱,結果雖然正確,但VS2005會提示該方法已過時,但仍能使用。
如果用它推薦的替代方法Dns.GetHostEntry,則有個別計算機的名稱會因超時而獲得不到。
4、端口掃描:利用TcpClient判斷端口是否打開
命名空間: System.Net.Sockets
程序集: System.Net.Sockets(在 System.Net.Sockets.dll 中)
System(在 System.dll 中)
delegate void WT2(); Thread t; private void scanport() { if (this.txtAddrs.InvokeRequired) { WT2 d = new WT2(scanport); this.Invoke(d, null); } else { try { TcpClient client = new TcpClient(); IPAddress address = IPAddress.Parse(txtIP.Text); for (int i = int.Parse(this.txtBegin.Text); i <= int.Parse(this.txtEnd.Text); i++) { try { client.Connect(address, i); txtAddrs.AppendText("端口 " + i + " 是打開的\n"); Console.WriteLine("端口{0}是打開的",i); client = new System.Net.Sockets.TcpClient(); } catch { } } } catch (Exception ex) { MessageBox.Show(ex.Message); } } }
附上兩個獲取局域網IP及其主機端口號的代碼
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Threading; using System.Net; using System.Net.NetworkInformation; using System.Runtime.InteropServices; using System.Collections.Specialized; using System.Net.Sockets; namespace 獲取局域網IP和MAC地址 { public partial class Form1 : Form { delegate void WT(int n); delegate void WT2(); Thread t; public Form1() { InitializeComponent(); } [DllImport("ws2_32.dll")] private static extern int inet_addr(string cp); [DllImport("IPHLPAPI.dll")] private static extern int SendARP(Int32 DestIP, Int32 ScrIP, ref Int64 pMacAddr, ref Int32 PhyAddrLen); //ref和out在C#中既可以通過值引用傳遞參數。通過引用參數傳遞參數允許函數成員更改參數的值 //並保持該更改。若要通過引用傳遞參數,可以使用ref或者out關鍵字。ref和out這兩個關鍵字都 //能夠提供相似的功效,其作用很像C中的指針變量 //使用ref型參數時,傳入的參數必須先被初始化。對out而言,必須在方法中對其完成初始化。 //使用ref和out時,在方法的參數和執行方法時,都要加Ref或Out關鍵字。以滿足匹配。 //out適合用在需要retrun多個返回值的地方,而ref則用在需要被調用的方法修改調用者的引用的時候。 private string GetMacAddress(string hostip)//獲取遠程IP(不能跨網段)的MAC地址 { string Mac = ""; try { Int32 ldest = inet_addr(hostip); //將IP地址從 點數格式轉換成無符號長整型 Int64 macinfo = new Int64(); Int32 len = 6; //SendARP函數發送一個地址解析協議(ARP)請求獲得指定的目的地IPv4地址相對應的物理地址 SendARP(ldest, 0, ref macinfo, ref len); string TmpMac = Convert.ToString(macinfo, 16).PadLeft(12, '0');//轉換成16進制 注意有些沒有十二位 Mac = TmpMac.Substring(0, 2).ToUpper();// for (int i = 2; i < TmpMac.Length; i = i + 2) { Mac = TmpMac.Substring(i, 2).ToUpper() + "-" + Mac; } } catch (Exception Mye) { Mac = "獲取遠程主機的MAC錯誤:" + Mye.Message; } return Mac; } private void button1_Click(object sender, EventArgs e) { this.txtMAC.Text = GetMacAddress(this.txtIP.Text.Trim()); } private List<string> ShowIP() { List<string> ipv4list = new List<string>(); //ipv4地址也可能不止一個 foreach (string ip in GetLocalIpv4()) { //this.richTextBoxIPv4.AppendText(ip.ToString()); //Console.WriteLine(ip.ToString()); ipv4list.Add(ip.ToString()); } return ipv4list; } private string[] GetLocalIpv4() { //事先不知道ip的個數,數組長度未知,因此用StringCollection儲存 IPAddress[] localIPs; localIPs = Dns.GetHostAddresses(Dns.GetHostName()); StringCollection IpCollection = new StringCollection(); foreach (IPAddress ip in localIPs) { //根據AddressFamily判斷是否為ipv4,如果是InterNetWorkV6則為ipv6 if (ip.AddressFamily == AddressFamily.InterNetwork) IpCollection.Add(ip.ToString()); } string[] IpArray = new string[IpCollection.Count]; IpCollection.CopyTo(IpArray, 0); return IpArray; } private void Form1_Load(object sender, EventArgs e) { List<string> list = ShowIP(); foreach(string str in list) { if(str.Contains("192.168.")) { txtIP.Text = str; } } } private void button3_Click(object sender, EventArgs e) { if (Dns.GetHostEntry(Dns.GetHostName()).AddressList.Length > 0) { txtAddrs.Text = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString();//獲取本機IPv6地址 } } private void EnumComputers2() { //從192.168.0.1 到 192.168.0.255開始依次嘗試 for (int i = 1; i <= 255; i++) { string scanIP = "192.168.0." + i.ToString(); IPAddress myScanIP = IPAddress.Parse(scanIP); IPHostEntry myScanHost = null; try { //獲取myScanIP的IP地址 myScanHost = Dns.GetHostByAddress(myScanIP); } catch { continue; } if (myScanHost != null) { //返回IP和主機名 Console.WriteLine(scanIP + "|" + myScanHost.HostName); } } } private void EnumComputers(int n) { //lock (this) //Invoke(new MethodInvoker(delegate() //{ //注冊委托 if (this.txtAddrs.InvokeRequired) { WT d = new WT(EnumComputers); this.Invoke(d, new object[] { n }); } else { try { for (int i = 0; i <= 255; i++) { Ping myPing; myPing = new Ping(); //當發送 Internet 控制消息協議 (ICMP) 回送消息並接收相應 ICMP 回送答復消息的異步操作完成或被取消時發生。 myPing.PingCompleted += new PingCompletedEventHandler(myPing_PingCompleted); string pingIP = "192.168." + n.ToString() + "." + i.ToString(); //嘗試以異步方式向指定的計算機發送Internet控制消息協議(ICMP)回送消息,並從該計算機接收相應的ICMP回送答復消息。 myPing.SendAsync(pingIP, 1000, null); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } //})); } private static int num = 0; private void myPing_PingCompleted(object sender, PingCompletedEventArgs e) { StringBuilder sb = new StringBuilder(); if (e.Reply.Status == IPStatus.Success) { sb.Append("IP:" + e.Reply.Address.ToString() + "\r\n"); //獲取MAC地址 string mac = GetMacAddress(e.Reply.Address.ToString()); sb.Append("MAC:" + mac + "\r\n\r\n"); num++; } this.txtAddrs.Text += sb.ToString(); //this.lbIPs.Text = "在線IP數:" + num.ToString(); this.lbIPs.Text = num.ToString(); } private void button2_Click(object sender, EventArgs e) { this.txtAddrs.Text = ""; num = 0; t = new Thread(() => EnumComputers((int)(this.txtIP2.Value))); t.IsBackground = true; t.Start(); //EnumComputers((int)(this.txtIP2.Value)); } private void button4_Click(object sender, EventArgs e) { t = new Thread(() => scanport()); t.IsBackground = true; t.Start(); } private void scanport() { if (this.txtAddrs.InvokeRequired) { WT2 d = new WT2(scanport); this.Invoke(d, null); } else { try { TcpClient client = new TcpClient(); IPAddress address = IPAddress.Parse(txtIP.Text); for (int i = int.Parse(this.txtBegin.Text); i <= int.Parse(this.txtEnd.Text); i++) { try { client.Connect(address, i); txtAddrs.AppendText("端口 " + i + " 是打開的\n"); Console.WriteLine("端口{0}是打開的",i); client = new System.Net.Sockets.TcpClient(); } catch { } } } catch (Exception ex) { MessageBox.Show(ex.Message); } } } private void txtIP2_ValueChanged(object sender, EventArgs e) { } } }
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.DirectoryServices; using System.Net.Sockets; using System.Threading; namespace 端口掃描 { public partial class Form1 : Form { #region //C# 操作WINNT本地用戶和組 DirectoryEntry DEMain = new DirectoryEntry("WinNT:"); TcpClient TClient = null; private Thread myThread; string strName = ""; int intflag = 0; int intport = 0; int intstart = 0; int intend = 0; #endregion public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { //遍歷局域網中的工作組,並顯示在下拉列表控件中 foreach(DirectoryEntry DEGroup in DEMain.Children) { comb_workgroup.Items.Add(DEGroup.Name); } } private void comb_workgroup_SelectedIndexChanged(object sender, EventArgs e) { listb_computer.Items.Clear(); //遍歷本地用戶組 foreach(DirectoryEntry DEGroup in DEMain.Children) { //如果和選擇的用戶組相同 if(DEGroup.Name.ToLower() == comb_workgroup.Text.ToLower()) { //讀出用戶組下的每一個主機名 foreach(DirectoryEntry DEComputer in DEGroup.Children) { //濾掉無效結果 Computer: Schema if(DEComputer.Name.ToLower() != "schema") { listb_computer.Items.Add(DEComputer.Name); } } } } } private void button1_Click(object sender, EventArgs e) { richtxt_port.Items.Clear(); try { if(button1.Text == "掃描") { intport = 0; progressBar1.Minimum = Convert.ToInt32(txt_beginport.Text); progressBar1.Maximum = Convert.ToInt32(txt_endport.Text); progressBar1.Value = progressBar1.Minimum; timer1.Start(); button1.Text = "停止"; intstart = Convert.ToInt32(txt_beginport.Text); intend = Convert.ToInt32(txt_endport.Text); myThread = new Thread(new ThreadStart(this.StartScan)); myThread.Start(); } else { button1.Text = "掃描"; timer1.Stop(); progressBar1.Value =Convert.ToInt32(txt_endport.Text); if(myThread != null) { if(myThread.ThreadState == ThreadState.Running) { myThread.Abort(); } } } } catch { } } private void StartScan() { while(true) { for(int i = intstart;i<=intend;i++) { intflag = i; try { TClient = new TcpClient(strName, i); intport = i; } catch { } } } } private void timer1_Tick(object sender, EventArgs e) { if(intport != 0) { if (richtxt_port.Items.Count > 0) { for (int i = 0; i < richtxt_port.Items.Count; i++) { if (richtxt_port.Items[i].Text != intport.ToString()) { richtxt_port.Items.Add(intport.ToString()); } } } else richtxt_port.Items.Add(intport.ToString()); } if (progressBar1.Value < progressBar1.Maximum) progressBar1.Value += 1; if(intflag == Convert.ToInt32(txt_endport.Text)) { timer1.Stop(); button1.Text = "掃描"; MessageBox.Show("端口掃描結束!"); } } } }