初做单线程和多线程实现端口扫描器

1.用 VS2017 新建一个 Windows 窗体应用(.NET Framework) 的项目

2.点击进入 From.cs[设计],界面设计如下:

在这里插入图片描述

3.端口扫描器(单线程)

3.1 代码

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.Net;
using System.Net.Sockets;
using System.Threading;

namespace WindowsFormsApp3
{
    
    
    public partial class Form1 : Form
    {
    
    
        public Form1()
        {
    
    
            InitializeComponent();
        }
        //主机地址
        private string hostAddress;
        //起始端口
        private int start;
        //终止端口
        private int end;
        //端口号
        private int port;
        //定义线程对象
        private Thread scanThread;

        private void label1_Click(object sender, EventArgs e)
        {
    
    

        }

        private void label1_Click_1(object sender, EventArgs e)
        {
    
    

        }

        private void button1_Click(object sender, EventArgs e)
        {
    
    
            try
            {
    
    
                //初始化
                textBox4.Clear();
                label5.Text = "0%";
                //获取ip地址和始末端口号
                hostAddress = textBox1.Text;
                start = Int32.Parse(textBox2.Text);
                end = Int32.Parse(textBox3.Text);
                if (decideAddress())
                {
    
    
                    //让输入的textbox只读,无法改变
                    textBox1.ReadOnly = true;
                    textBox2.ReadOnly = true;
                    textBox3.ReadOnly = true;
                    //设置进度条的范围
                    progressBar1.Minimum = start;
                    progressBar1.Maximum = end;
                    //显示框显示
                    textBox4.AppendText("端口扫描器 v1.0.0" + Environment.NewLine + Environment.NewLine);
                    //调用端口扫描函数
                    PortScan();
                }
                else
                {
    
    
                    //若端口号不合理,弹窗报错
                    MessageBox.Show("输入错误,端口范围为[0-65536]!");
                }
            }
            catch
            {
    
    
                //若输入的端口号为非整型,则弹窗报错
                MessageBox.Show("输入错误,端口范围为[0-65536]!");
            }
        }
        private bool decideAddress()
        {
    
    
            //判断端口号是否合理
            if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
                return true;
            else
                return false;
        }

        private void PortScan()
        {
    
    
            double x;
            string xian;
            //显示扫描状态
            textBox4.AppendText("开始扫描...(可能需要请您等待几分钟)" + Environment.NewLine + Environment.NewLine);
            //循环抛出线程扫描端口
            for (int i = start; i <= end; i++)
            {
    
    
                x = (double)(i - start + 1) / (end - start + 1);
                xian = x.ToString("0%");
                port = i;
                //调用端口i的扫描操作
                Scan();
                //进度条值改变
                label5.Text = xian;
                label5.Refresh();
                progressBar1.Value = i;
            }
            textBox3.AppendText(Environment.NewLine + "扫描结束!" + Environment.NewLine);
            //输入框textbox只读属性取消
            textBox1.ReadOnly = false;
            textBox2.ReadOnly = false;
            textBox3.ReadOnly = false;
        }

        private void Scan()
        {
    
    
            int portnow = port;
            //创建TcpClient对象,TcpClient用于为TCP网络服务提供客户端连接
            TcpClient objTCP = null;
            try
            {
    
    
                //用于TcpClient对象扫描端口
                objTCP = new TcpClient(hostAddress, portnow);
                //扫描到则显示到显示框
                textBox3.AppendText("端口 " + port + " 开放!" + Environment.NewLine);
            }
            catch
            {
    
    
                //未扫描到,则会抛出错误
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
    
    

        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
    
    

        }
    }
}

3.2 执行结果

127.0.0.1这个 IP 地址代指自己的主机,不能用自己主机真实的 IP 地址。
在这里插入图片描述

4.端口扫描器(多线程)

4.1代码

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.Net;
using System.Net.Sockets;
using System.Threading;

namespace WindowsFormsApp3
{
    
    
    public partial class Form1 : Form
    {
    
    
        public Form1()
        {
    
    
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
        }
        //主机地址
        private string hostAddress;
        //起始端口
        private int start;
        //终止端口
        private int end;
        //端口号
        private int port;
        //定义线程对象
        private Thread scanThread;
        private bool[] done = new bool[65526];
        private bool OK;

        private void label1_Click(object sender, EventArgs e)
        {
    
    

        }

        private void label1_Click_1(object sender, EventArgs e)
        {
    
    

        }
        private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
    
    

        }


        private void textBox4_TextChanged(object sender, EventArgs e)
        {
    
    

        }

        private void progressBar1_Click(object sender, EventArgs e)
        {
    
    

        }
        private void label4_Click(object sender, EventArgs e)
        {
    
    

        }
        private void button1_Click(object sender, EventArgs e)
        {
    
    
            try
            {
    
    
                //初始化
                textBox4.Clear();
                label5.Text = "0%";
                //获取ip地址和始末端口号
                hostAddress = textBox1.Text;
                start = Int32.Parse(textBox2.Text);
                end = Int32.Parse(textBox3.Text);
                if (decideAddress())
                {
    
    
                    //让输入的textbox只读,无法改变
                    textBox1.ReadOnly = true;
                    textBox2.ReadOnly = true;
                    textBox3.ReadOnly = true;
                    //设置进度条的范围
                    progressBar1.Minimum = start;
                    progressBar1.Maximum = end;
                    //显示框显示
                    textBox4.AppendText("端口扫描器 v1.0.0" + Environment.NewLine + Environment.NewLine);
                    //调用端口扫描函数
                    PortScan();
                }
                else
                {
    
    
                    //若端口号不合理,弹窗报错
                    MessageBox.Show("输入错误,端口范围为[0-65536]!");
                }
            }
            catch
            {
    
    
                //若输入的端口号为非整型,则弹窗报错
                MessageBox.Show("输入错误,端口范围为[0-65536]!");
            }
        }
        private bool decideAddress()
        {
    
    
            //判断端口号是否合理
            if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
                return true;
            else
                return false;
        }

        private void PortScan()
        {
    
    
            double x;
            string xian;
            //显示扫描状态
            textBox4.AppendText("开始扫描...(可能需要请您等待几分钟)" + Environment.NewLine + Environment.NewLine);
            //循环抛出线程扫描端口
            for (int i = start; i <= end; i++)
            {
    
    
                x = (double)(i - start + 1) / (end - start + 1);
                xian = x.ToString("0%");
                port = i;
                //使用该端口的扫描线程
                scanThread = new Thread(new ThreadStart(Scan));
                scanThread.Start();
                //使线程睡眠
                System.Threading.Thread.Sleep(100);
                //进度条值改变
                label5.Text = xian;
                progressBar1.Value = i;
            }
            while (!OK)
            {
    
    
                OK = true;
                for (int i = start; i <= end; i++)
                {
    
    
                    if (!done[i])
                    {
    
    
                        OK = false;
                        break;
                    }
                }
                System.Threading.Thread.Sleep(1000);
            }
            textBox4.AppendText(Environment.NewLine + "扫描结束!" + Environment.NewLine);
            textBox1.ReadOnly = false;
            textBox2.ReadOnly = false;
            textBox3.ReadOnly = false;
        }

        private void Scan()
        {
    
    
            int portnow = port;
            //创建线程变量
            Thread Threadnow = scanThread;
            //扫描端口,成功则写入信息
            done[portnow] = true;
            //创建TcpClient对象,TcpClient用于为TCP网络服务提供客户端连接
            TcpClient objTCP = null;
            try
            {
    
    
                //用于TcpClient对象扫描端口
                objTCP = new TcpClient(hostAddress, portnow);
                //扫描到则显示到显示框
                textBox4.AppendText("端口 " + port + " 开放!" + Environment.NewLine);
            }
            catch
            {
    
    
                //未扫描到,则会抛出错误
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
    
    

        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
    
    

        }
    }
}

4.2执行结构

在这里插入图片描述

如图可知多线程比单线程的速度快了很多倍。

5.总结

初步学习了使用单线程和多线程实现端口扫描器,其中多线程就好比是把单线程的总量分成了多条线路同时进行,自然是要快很多,目前绝大多数的应用程序都是采用的多线程,掌握多线程编程是一个实战程序员应会的技能,但跨线程控制控件,会遇到问题,子线程控制主线程的控件,会容易造成死循环,在C#当中是采用委托来解决这一问题。

猜你喜欢

转载自blog.csdn.net/qq_48008050/article/details/109778411