zoukankan      html  css  js  c++  java
  • 如何高效实现扫描局域网IP、主机名、MAC和端口

       近几年工作经常使用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 + "   毫秒
    ";
                            mac= GetMacAddress(ipaddr);
                         //   IPHostEntry host = Dns.GetHostEntry(ipaddr);
                            // IPHostEntry host = Dns.GetHostByAddress(ipaddr);
                            // ResuleTextBox.Text += "主机名为    " + host.HostName + "
    ";
                            // 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地址扫描中---
    ";
                    //---------------------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 + "毫秒
    ";
                        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 + "
    ";
                    }
                    else
                    {
                        //    ScanResultlistBox.Items.Add(ipaddr + "                              " + "-" + "            " + "-" + "   " + "                - 不可达
    ");
                        lvi = new ListViewItem();
                        lvi.BackColor = Color.Pink;
                        lvi.Text = ipaddr;
                        lvi.SubItems.Add("-");
                        lvi.SubItems.Add("-");
                        lvi.SubItems.Add("不可达");
                        ResuleTextBox.Text += ipaddr + "不可达
    ";
                        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 + " 端口扫描中---
    ";
    
                        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 += "
    ";
                }
                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

  • 相关阅读:
    matlab中plot画图参数的设置
    TOF相机基本知识
    工业相机接口选择
    工业相机基本知识
    TwinCAT 3中基于UDP协议通讯的C++实现
    投影几何中的无穷远量
    基于CANopen DSP402的运动控制笔记
    C++ new 的用法
    C++中static用法总结
    设计模式——适配器模式(Adapter Pattern)
  • 原文地址:https://www.cnblogs.com/kmust/p/6685752.html
Copyright © 2011-2022 走看看