基于C#实现端口扫描器(单线程和多线程)

2021-12-01

目录
  • 一、新建项目并设置界面
  • 二、单线程实现端口扫描
    • 1. 编写代码
    • 2. 运行结果
  • 三、多线程实现端口扫描
    • 1. 编写代码
    • 2. 运行结果
  • 四、总结

    一、新建项目并设置界面

    新建项目:

    选择Windows窗体项目应用(.Net Framework):

    设置项目名和路径:

    新建项目如下:

    设置界面:

    将tbShow设置为只读:

    二、单线程实现端口扫描

    1. 编写代码

    双击按钮,编写其点击事件:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace Scan
    {
        public partial class Form1 : Form
        {
    
    
            //主机地址
            private string hostAddress;
            //起始端口
            private int start;
            //终止端口
            private int end;
            //端口号
            private int port;
            //定义线程对象
            private Thread scanThread;
            
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click_1(object sender, EventArgs e)
            {
                try
                {
                    //初始化
                    tbShow.Clear();
                    lb.Text = "0%";
    
                    //获取ip地址和始末端口号
                    hostAddress = tbHost.Text;
                    start = Int32.Parse(tbSPort.Text);
                    end = Int32.Parse(tbEPort.Text);
    
                    if (decideAddress()) // 端口合理
                    {
                        //让输入的textbox只读,无法改变
                        tbHost.ReadOnly = true;
                        tbSPort.ReadOnly = true;
                        tbEPort.ReadOnly = true;
                        //设置进度条的范围
                        pb.Minimum = start;
                        pb.Maximum = end;
    
                        //显示框显示
                        tbShow.AppendText("端口扫描器 v1.0.0" + Environment.NewLine + Environment.NewLine);
                        //调用端口扫描函数
                        PortScan();
                    }
                    else
                    {
                    	//若端口号不合理,弹窗报错
                        MessageBox.Show("输入错误,端口范围为[0-65536]!");
                    }
                }
                catch
                {
    				//若输入的端口号为非整型,则弹窗报错
                    MessageBox.Show("输入错误,端口范围为[0-65536]!");
                }
            }
    
            /// <summary>
            /// 判断端口是否合理
            /// </summary>
            /// <returns></returns>
            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;
                //显示扫描状态
                tbShow.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();
                    //进度条值改变
                    lb.Text = xian;
                    lb.Refresh();
                    pb.Value = i;
                }
                tbShow.AppendText(Environment.NewLine + "扫描结束!" + Environment.NewLine);
                //输入框textbox只读属性取消
                tbHost.ReadOnly = false;
                tbSPort.ReadOnly = false;
                tbEPort.ReadOnly = false;
            }
    
            /// <summary>
            /// 扫描某个端口
            /// </summary>
            private void Scan()
            {
                int portnow = port;
                //创建TcpClient对象,TcpClient用于为TCP网络服务提供客户端连接
                TcpClient objTCP = null;
                try
                {
                    //用于TcpClient对象扫描端口
                    objTCP = new TcpClient(hostAddress, portnow);
                    //扫描到则显示到显示框
                    tbShow.AppendText("端口 " + port + " 开放!" + Environment.NewLine);
                }
                catch
                {
                    //未扫描到,则会抛出错误
                }
            }
    
    
        }
    }
    

    2. 运行结果

    可发现速度十分缓慢,且不能拖拽。

    三、多线程实现端口扫描

    1. 编写代码

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace Scan
    {
        public partial class Form1 : Form
        {
    
    
            //主机地址
            private string hostAddress;
            //起始端口
            private int start;
            //终止端口
            private int end;
            //端口号
            private int port;
            //定义线程对象
            private Thread scanThread;
            //定义端口状态数据(开放则为true,否则为false)
            private bool[] done = new bool[65526];
            private bool OK;
    
    
            public Form1()
            {
                InitializeComponent();
                //不进行跨线程检查
                CheckForIllegalCrossThreadCalls = false;
            }
    
            private void button1_Click_1(object sender, EventArgs e)
            {
                try
                {
                    //初始化
                    tbShow.Clear();
                    lb.Text = "0%";
    
                    //获取ip地址和始末端口号
                    hostAddress = tbHost.Text;
                    start = Int32.Parse(tbSPort.Text);
                    end = Int32.Parse(tbEPort.Text);
    
                    if (decideAddress()) // 端口合理
                    {
                        //让输入的textbox只读,无法改变
                        tbHost.ReadOnly = true;
                        tbSPort.ReadOnly = true;
                        tbEPort.ReadOnly = true;
                        //创建线程,并创建ThreadStart委托对象
                        Thread process = new Thread(new ThreadStart(PortScan));
                        process.Start();
                        //设置进度条的范围
                        pb.Minimum = start;
                        pb.Maximum = end;
    
                        //显示框显示
                        tbShow.AppendText("端口扫描器 v1.0.0" + Environment.NewLine + Environment.NewLine);
                    }
                    else
                    {
                        //若端口号不合理,弹窗报错
                        MessageBox.Show("输入错误,端口范围为[0-65536]!");
                    }
    
                }
                catch
                {
                    //若输入的端口号为非整型,则弹窗报错
                    MessageBox.Show("输入错误,端口范围为[0-65536]!");
                }
            }
    
            /// <summary>
            /// 判断端口是否合理
            /// </summary>
            /// <returns></returns>
            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;
                //显示扫描状态
                tbShow.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);
                    //进度条值改变
                    lb.Text = xian;
                    pb.Value = i;
                }
                while (!OK)
                {
                    OK = true;
                    for (int i = start; i <= end; i++)
                    {
                        if (!done[i])
                        {
                            OK = false;
                            break;
                        }
                    }
                    System.Threading.Thread.Sleep(1000);
                }
                tbShow.AppendText(Environment.NewLine + "扫描结束!" + Environment.NewLine);
                //输入框textbox只读属性取消
                tbHost.ReadOnly = false;
                tbSPort.ReadOnly = false;
                tbEPort.ReadOnly = false;
            }
    
            /// <summary>
            /// 扫描某个端口
            /// </summary>
            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);
                    //扫描到则显示到显示框
                    tbShow.AppendText("端口 " + port + " 开放!" + Environment.NewLine);
                }
                catch
                {
                    //未扫描到,则会抛出错误
                }
            }
    
    
        }
    }
    

    2. 运行结果

    可发现速度明显变快,且能拖拽窗口。

    四、总结

    多线程可以提高CPU的利用率。

    以上就是基于C#实现端口扫描器(单线程和多线程)的详细内容,更多关于C# 端口扫描器的资料请关注北冥有鱼其它相关文章!

    《基于C#实现端口扫描器(单线程和多线程).doc》

    下载本文的Word格式文档,以方便收藏与打印。