C#獲取局域網IP、MAC地址和端口的初學


首先非常感謝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);
                }
            }
        } 

 

 

效果評價:效率低,速度慢,不是一般的慢。

 

 

3、使用System.Net.NetworkInformation.Ping來遍歷局域網

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));
        }
效果評價:速度快,效率高,如果只取在線的IP,不取計算機名,速度會更快。
需要注意的是取計算機名稱如果用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("端口掃描結束!");
            }
        }
    }
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM