如何高效實現掃描區域網IP、主機名、MAC和埠

badwell發表於2017-04-09

   近幾年工作經常使用RFID識讀器,智慧家居閘道器,溫溼度感測器、串列埠伺服器、視訊編碼器等,一般是有串列埠和網口,由於現場原因一般較少使用串列埠,大多使用網口。連線方法是IP地址和埠,有的裝置帶搜尋軟體,有的就不帶。經常測試環境和現場來回用,難免記混。同時使用網上的一些埠掃描工具,發現有一個問題,就是在進行掃描的時候,不怎麼好用,比如,掃描器一般都是帶埠掃描的,但是,我僅僅只用掃描裝置在不線上,不用掃描埠,但是有一些裝置是隻要掃描埠,這個怎麼更方便更好用呢?

   同時在掃描成功之後,需要通過TCP連線到裝置,發資料,看資料能不能正常相應,或者裝置狀態對不對,這是不是又要單獨開另外一個軟體?使用起來,比較繁瑣,因此就根據自己的需要製作了一個小工具,用來掃描IP和埠。

 掃描速度一定要快,成功和不成功區分要明顯,好了,先上圖:

 

一、主要IP掃描方法:

(1)、IP地址匹配,看IP設定是否正確

   //匹配正確的IP地址
            Regex rgx = new Regex(@"^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$");

            if (rgx.IsMatch(IPStarttextBox.Text) && rgx.IsMatch(IPStoptextBox.Text))//匹配正確IP
            {
                if (scan_type == 1)
                {
                    int startIp = Int32.Parse(IPStarttextBox.Text.Split('.')[3]);
                    int endIp = Int32.Parse(IPStoptextBox.Text.Split('.')[3]);
                    progressBar.Minimum = startIp;
                    progressBar.Maximum = endIp;
                }
                else
                {
                    if (PortStarttextBox.Text == "")
                    {
                        MessageBox.Show("請輸入埠號!");
                    }
                    else
                    {
                        portStart = Int32.Parse(PortStarttextBox.Text);
                        portEnd = Int32.Parse(PortEndtextBox.Text);
                        progressBar.Minimum = portStart;
                        progressBar.Maximum = portEnd;
                    }

                    if (portEnd < portStart)
                    {
                        MessageBox.Show("請填寫正確埠範圍");
                        return;
                    }
                }

            }
            else
            {
                MessageBox.Show("請填寫正確IP");
                return;
            }

 (2)、獲取主機名

   public static string GetHostEntry(object ip)
        {
            string hostname = "-";   
            try
            {
                IPHostEntry host = Dns.GetHostEntry(ip.ToString());
                hostname = host.HostName;
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            return hostname;
        }

(3)、獲取MAC地址

 [DllImport("ws2_32.dll")]
        private static extern int inet_addr(string cp);
        [DllImport("IPHLPAPI.dll")]
        private static extern int SendARP(Int32 DestIP, Int32 SrcIP, ref Int64 pMacAddr, ref Int32 PhyAddrLen);


        private string GetMacAddress(string hostip)//獲取遠端IP(不能跨網段)的MAC地址
        {
            string Mac = "";
            try
            {
                Int32 ldest = inet_addr(hostip); //將IP地址從 點數格式轉換成無符號長整型
                Int64 macinfo = new Int64();
                Int32 len = 6;
                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;
        }

(3)、主要準備工作做好了,接下來,進入主題,如何通過多執行緒判斷IP是否線上。

Thread waitT = new Thread(new ThreadStart(ipwait));
                waitT.Start();//等待所有執行緒執行完畢在寫入textbox中

 public void ipwait()
        {
            int startIp = Int32.Parse(IPStarttextBox.Text.Split('.')[3]);
            int endIp = Int32.Parse(IPStoptextBox.Text.Split('.')[3]);
            ListViewItem lvi;

            string ip = IPStarttextBox.Text.Split('.')[0] + "." + IPStarttextBox.Text.Split('.')[1] + "." + IPStarttextBox.Text.Split('.')[2] + ".";
            String ipaddr = "";
            int timeout = int.Parse(TimeOuttextBox.Text);

            string mac = "";

            progressBar.Minimum = startIp;
            progressBar.Maximum = endIp;
            try
            {

                for (int q = startIp; q <= endIp && isrun == true; q++)
                {

                    //---------------------ping
                    ipaddr = ip + q;
                    lvi  = new ListViewItem();
                    Ping ping = new Ping();
                    PingReply reply = ping.Send(IPAddress.Parse(ipaddr), overTime);

                    if (reply.Status == IPStatus.Success)
                    {

                        ResuleTextBox.Text += ipaddr + "    Ping時間   " + reply.RoundtripTime + "   毫秒\n";
                        mac= GetMacAddress(ipaddr);
                     //   IPHostEntry host = Dns.GetHostEntry(ipaddr);
                        // IPHostEntry host = Dns.GetHostByAddress(ipaddr);
                        // ResuleTextBox.Text += "主機名為    " + host.HostName + "\n";
                        // ScanResultlistBox.Items.Add(ipaddr + "                    " + mac + "                 線上   ");
                        lvi.BackColor = Color.LightSeaGreen;
                        lvi.Text = ipaddr;
                        Task<string> t1 = new Task<string>(GetHostEntry,ipaddr);
                        t1.Start();
                        t1.Wait(timeout);   //設定獲取主機名超時時間
                        if(t1.IsCompleted)
                        {
                            lvi.SubItems.Add(t1.Result);
                        }
                        else
                        {
                            lvi.SubItems.Add("-");
                        }
                        lvi.SubItems.Add(mac);
                        lvi.SubItems.Add("線上");

                    }
                    else
                    {
                        lvi.BackColor = Color.Pink;
                        lvi.Text = ipaddr;
                        lvi.SubItems.Add("-");
                        lvi.SubItems.Add("-");
                        lvi.SubItems.Add("不線上");
                    }

                    progressBar.Value = q;
                    progressBar.Update();
                    ListViewUpdate(lvi);
                    ResuleTextBox.SelectionStart = ResuleTextBox.Text.Length -1;
                    ResuleTextBox.ScrollToCaret();
                }
                ScanResultlistBox.Items[ScanResultlistBox.Items.Count - 1].EnsureVisible();

            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
                isrun = false;
                progressBar.Value = progressBar.Minimum;
                startScanbutton.Enabled = true;
                stopScanbutton.Enabled = false;
                ResuleTextBox.Text += ex.ToString();
            }
            startScanbutton.Enabled = true;
            stopScanbutton.Enabled = false;
            isrun = false;
            progressBar.Value = progressBar.Maximum;

        }

說明一下:在我獲取主機名的過程中,發現如果不對獲取主機名設定一個超時時間,那麼將會出現一個問題,程式將會卡在獲取主機名的這個階段,無法向下繼續執行,因為,為了高效的執行,給獲取主機名設定一個超時時間,將會大大提高程式的執行效率。

 二、主要埠狀態獲取方法

 Thread waitT = new Thread(new ThreadStart(portwait));
                waitT.Start();//等待所有執行緒執行完畢在寫入textbox中
   public void portwait()
        {
            int startIp = Int32.Parse(IPStarttextBox.Text.Split('.')[3]);
            int endIp = Int32.Parse(IPStoptextBox.Text.Split('.')[3]);

            string ip = IPStarttextBox.Text.Split('.')[0] + "." + IPStarttextBox.Text.Split('.')[1] + "." + IPStarttextBox.Text.Split('.')[2] + ".";
            String mac = "" , ipaddr ="";
            ListViewItem lvi;
            String host;
            int timeout = int.Parse(TimeOuttextBox.Text);
            for (int q = startIp; q <= endIp && isrun == true; q++)
            {
                ResuleTextBox.Text += (ip + q) + " IP地址掃描中---\n";
                //---------------------ping
                Ping ping = new Ping();
             
                PingReply reply = ping.Send(IPAddress.Parse(ip + q), overTime);
                ipaddr = ip + q;
                if (reply.Status == IPStatus.Success)
                {
                    ResuleTextBox.Text +=ipaddr  + " Ping時間" + reply.RoundtripTime + "毫秒\n";
                    mac = GetMacAddress(ipaddr);
                    Task<string> t1 = new Task<string>(GetHostEntry, ipaddr);
                    t1.Start();
                    t1.Wait(timeout);
                    if (t1.IsCompleted)
                    {
                        host = t1.Result.ToString();
                    }
                    else
                    {
                        host = "-";
                    }
                    ResuleTextBox.Text += "MAC地址為 " + mac + "\n";
                }
                else
                {
                    //    ScanResultlistBox.Items.Add(ipaddr + "                              " + "-" + "            " + "-" + "   " + "                - 不可達\n");
                    lvi = new ListViewItem();
                    lvi.BackColor = Color.Pink;
                    lvi.Text = ipaddr;
                    lvi.SubItems.Add("-");
                    lvi.SubItems.Add("-");
                    lvi.SubItems.Add("不可達");
                    ResuleTextBox.Text += ipaddr + "不可達\n";
                    ListViewUpdate(lvi);
                    continue;
                }





                //---------------------end
                Thread[] tharr;
                if (numThread < (portEnd - portStart + 1))
                {
                    tharr = new Thread[portEnd - portStart + 1];
                }
                else
                {
                    tharr = new Thread[numThread];
                }
                str = new List<string>();
                for (int i = portStart; (i <= portEnd) && (isrun ==true); i++)
                {
                    Thread thread = new Thread(new ParameterizedThreadStart(Scan));
                    thread.Start(new IPEndPoint(IPAddress.Parse(ip + q), i));//每掃描一個埠建立一個執行緒

                    ResuleTextBox.Text += i + " 埠掃描中---\n";

                    tharr[i - portStart] = thread;
                    progressBar.Value = i;

                    string s = State(i);

                    lvi = new ListViewItem();

                    if (s == "Open")
                    {
                        lvi.BackColor = Color.LightSeaGreen;
                    }
                    else
                    {
                        lvi.BackColor = Color.Silver;
                    }

                    lvi.Text = ipaddr + ":" + i.ToString();
                    lvi.SubItems.Add(host);
                    lvi.SubItems.Add(mac);

                    if (checkBox1.Checked)
                    {
                        if (s == "Open")
                        {

                            //  ScanResultlistBox.Items.Add(ip + q + "                       " + mac +"        "+ i + "           " + s + "   " + "          " + Service(i));
                         
                            lvi.SubItems.Add(i.ToString());
                            lvi.SubItems.Add(s);
                            lvi.SubItems.Add(Service(i));
                        }
                        else
                        {
                            lvi = null;
                        }
                    }
                    else
                    {
                        if (s == "Open")
                        {

                            //   ScanResultlistBox.Items.Add(ip + q + "                      " + mac + "        " + i + "              " + s + "   " + "         " + Service(i));
                           
                            lvi.SubItems.Add(i.ToString());
                            lvi.SubItems.Add(s);
                            lvi.SubItems.Add(Service(i));
                        }
                        else
                        {
                            //   ScanResultlistBox.Items.Add(ip + q + "                       " + mac + "        " + i + "            " + s + "   " + "          ");
                          
                            lvi.SubItems.Add(i.ToString());
                            lvi.SubItems.Add(s);
                            lvi.SubItems.Add("");
                        }
                    }
                    if (lvi != null)
                    {
                        ListViewUpdate(lvi);
                    }
                }


                bool iscon = true;//第一個執行緒等待時間
                for (int i = 0; i < tharr.Length; i++)
                {
                    if (tharr[i] == null)
                        continue;
                    while (tharr[i].IsAlive && iscon)//埠超時設定時間(目前200毫秒),一直等待此ip所有執行緒執行完畢才掃描下個ip
                    {
                        Thread.Sleep(200);
                        iscon = false;//第一個執行緒給200ms等待時間,其他執行緒由於同步執行的,所以沒等待時間了,如果執行緒還沒執行完,說明此埠不可達。
                    }
                }
                str.Sort();
                ResuleTextBox.Text += "開放埠: ";
                for (int k = 0; k < str.Count; k++)
                    ResuleTextBox.Text += str[k] + "  ";
                ResuleTextBox.Text += "\n";
            }
            ScanResultlistBox.Items[ScanResultlistBox.Items.Count - 1].EnsureVisible();
            if (isrun == true)
            {
                MessageBox.Show("掃描完成");
                progressBar.Value = progressBar.Minimum;
                startScanbutton.Enabled = true;
                stopScanbutton.Enabled = false;
                isrun = false;
            }
            else
            {
                MessageBox.Show("掃描終止");
                startScanbutton.Enabled = true;
                stopScanbutton.Enabled = false;
                progressBar.Value = progressBar.Minimum;
                isrun = false;
            }


        }
        public string State(int i)
        {
            str.Sort();
            for (int k = 0; k < str.Count; k++)
            {
                string s = str[k];
                if (Convert.ToString(i) == s)
                    return "Open";
            }
            return "Closed";
        }
        public string Service(int i)
        {
            switch (i)
            {

                case 80:
                    return "HTTP協議代理服務";
                case 135:
                    return "DCE endpoint resolutionnetbios-ns";
                case 445:
                    return "安全服務";
                case 1025:
                    return "NetSpy.698(YAI)";


                case 8080:
                    return "HTTP協議代理服務";

                case 8081:
                    return "HTTP協議代理服務";

                case 3128:
                    return "HTTP協議代理服務";

                case 9080:
                    return "HTTP協議代理服務";

                case 1080:
                    return "SOCKS代理協議服務";

                case 21:
                    return "FTP(檔案傳輸)協議代理服務";

                case 23:
                    return "Telnet(遠端登入)協議代理服務";

                case 443:
                    return "HTTPS協議代理服務";

                case 69:
                    return "TFTP協議代理服務";

                case 22:
                    return "SSH、SCP、埠重定向協議代理服務";

                case 25:
                    return "SMTP協議代理服務";

                case 110:
                    return "POP3協議代理服務";
                default:
                    return "Unknow Servies";



            }
        }

        public void Scan(object Point)
        {
            IPEndPoint IPPoint = (IPEndPoint)Point;
            try
            {
                TcpClient tcp = new TcpClient();
                tcp.Connect(IPPoint);
                if (tcp.Connected)
                    str.Add(Convert.ToString(IPPoint.Port));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

好了,大家最後,可能都會說,我不想設計,也不想開發,我想要現成的怎麼辦?當然了,最後附上程式,大家可以實際進行測試使用。

工具連結:http://download.csdn.net/detail/dwx1005526886/9808540

相關文章