C#端口扫描器程序(单线程和多线程)

一、单线程与多线程的区别

  1. 单线程:
    每个正在运行的程序(即进程),至少包括一个线程,这个线程叫主线程
    主线程在程序启动时被创建,用于执行main函数
    只有一个主线程的程序,称作单线程程序
    主线程负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等等)。这些代码只能顺序执行,无法并发执行
  2. 多线程:
    拥有多个线程的程序,称作多线程程序。
    允许用户自己开辟新的线程,相对于主线程来讲,这些线程,称为子线程
    可以根据需要开辟若干子线程
    子线程和主线程都是独立的运行单元,各自的执行互不影响,因此能够并发执行
  3. 单线程、多线程的区别:
    单线程程序:只有一个线程,代码顺序执行,容易出现代码阻塞(页面假死)
    多线程程序:有多个线程,线程间独立运行,能有效地避免代码阻塞,并且提高程序的运行性能

二、端口扫描程序设计

1. 创建项目

  • 选择windows窗体应用

在这里插入图片描述

  • 项目配置
    在这里插入图片描述
  • 初始界面
    在这里插入图片描述

2. 界面设计

在这里插入图片描述

3. 单线程代码

namespace ScanPort_Single
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//设置该属性 为false,将禁止捕获对错误线程的调用
        }
        //自定义变量
        //单线程
        
        private int port;//记录当前扫描的端口号
        private string Address;//记录扫描的系统地址
        private bool[] done = new bool[65536];//记录端口的开放状态
        private int start;//记录扫描的起始端口
        private int end;//记录扫描的结束端口
        private bool OK;
        
        private void button1_Click(object sender, EventArgs e)
        {
            start = Int32.Parse(textBox2.Text);
            end = Int32.Parse(textBox3.Text);
            label4.Text = start.ToString();
            label6.Text = end.ToString();
            label4.Visible = true;
            label6.Visible = true;
            progressBar1.Minimum = Int32.Parse(textBox2.Text);
            progressBar1.Maximum = Int32.Parse(textBox3.Text);
            listBox1.Items.Clear();
            listBox1.Items.Add("端口扫描器v1.0.");
            listBox1.Items.Add("");
            PortScan();

        }
        private void PortScan()
        {
           
            //判断输入端口是否合法
            if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
            {
                listBox1.Items.Add("开始扫描:这个过程可能需要等待几分钟!");
                Address = textBox1.Text;
                for (int i = start; i <= end; i++)
                {
                    port = i;
                    Scan();
                    progressBar1.Value = i;
                    label5.Text = i.ToString();
                    label5.Visible = true;
                }
                while (!OK)
                {
                    OK = true;
                    for (int i = start; i <= end; i++)
                    {
                        if (!done[i])
                        {
                            OK = false;
                            break;
                        }
                    }
                }
                listBox1.Items.Add("扫描结束!");
            }
            else
            {
                MessageBox.Show("输入错误,端口范围为[0,65536]");
            }
        }
        //连接端口
        private void Scan()
        {
            int portnow = port;
            done[portnow] = true;
            TcpClient objTCP = null;
            try
            {
                objTCP = new TcpClient(Address, portnow);
                listBox1.Items.Add("端口" + portnow.ToString() + "开放");
            }
            catch
            {

            }

        }
    }
}

4. 多线程代码

namespace ScanPort_Single
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//设置该属性 为false,将禁止捕获对错误线程的调用
        }
        //自定义变量     
        private int port;//记录当前扫描的端口号
        private string Address;//记录扫描的系统地址
        private bool[] done = new bool[65536];//记录端口的开放状态
        private int start;//记录扫描的起始端口
        private int end;//记录扫描的结束端口
        private bool OK;
       
        //多线程
        private Thread scanThread;
        private void label4_TextChanged(object sender, EventArgs e)
        {
            label4.Text = textBox2.Text;
            label4.Visible = true;
        }
        //将输入的结束地址放到进度条的结束位置
        private void label6_TextChanged(object sender, EventArgs e)
        {
            label6.Text = textBox3.Text;
            label6.Visible = true;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            label4_TextChanged(sender, e);
            label6_TextChanged(sender, e);

            //创建线程,并创建ThreadStart委托对象
            Thread procss = new Thread(new ThreadStart(ScanPort_Thread));
            procss.Start();
            //显示端口扫描范围
            progressBar1.Minimum = Int32.Parse(textBox2.Text);
            progressBar1.Maximum = Int32.Parse(textBox3.Text);
            listBox1.Items.Clear();
            listBox1.Items.Add("端口扫描器v1.0.");
            listBox1.Items.Add("");
            ScanPort_Thread();
        }
        private void ScanPort_Thread()
        {
            start = Int32.Parse(textBox2.Text);
            end = Int32.Parse(textBox3.Text);
            //判断输入端口是否合法
            if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
            {             
                listBox1.Items.Add("开始扫描:这个过程可能需要等待几分钟!");
                Address = textBox1.Text;
                for (int i = start; i <= end; i++)
                {
                    port = i;
                    //对该端口进行扫描的线程
                    scanThread = new Thread(Scan);
                    scanThread.Start();
                    //使线程睡眠
                    System.Threading.Thread.Sleep(100);
                    progressBar1.Value = i;
                    label5.Text = i.ToString();
                    label5.Visible = true;
                }
                //未完成时情况
                while (!OK)
                {
                    OK = true;
                    for (int i = start; i <= end; i++)
                    {
                        if (!done[i])
                        {
                            OK = false;
                            break;
                        }
                    }
                }
                listBox1.Items.Add("扫描结束!");
                System.Threading.Thread.Sleep(1000);
            }
            else
            {
                MessageBox.Show("输入错误,端口范围为[0,65536]");
            }
        }
        //连接端口
        private void Scan()
        {
            int portnow = port;
            //创建线程变量
            Thread Threadnow = scanThread;
            done[portnow] = true;
            //创建TcpClient对象,TcpClient用于TCP网络服务提供客户端连接
            TcpClient objTCP = null;
            //扫描端口,成功就写入信息
            try
            {
                objTCP = new TcpClient(Address, portnow);
                listBox1.Items.Add("端口" + portnow.ToString() + "开放!");
            }
            catch
            {

            }

        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }
    }
}

说明:当使用多线程功能时,在子线程里修改UI控件参数时,会报错

异常:System.InvalidOperationException:“线程间操作无效: 从不是创建控件“listBox1”的线程访问它。”

解决办法在Form1重载中写上一行代码

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//设置该属性 为false,将禁止捕获对错误线程的调用

也可以

listBox1.Invoke(new EventHandler(delegate
	{
	//其他线程创建的控件的参数的一些修改语句
	}));

三、端口扫描程序运行效果

1. 单线程

在这里插入图片描述

2. 多线程

在这里插入图片描述
在这里插入图片描述
整个过程使用多个线程来实现扫描端口,次线程的进行并不会影响主线程的进行,线程之间不会相互影响。
对比单线程,多线程时间明显更短,单线程会出现卡顿的情况,而多线程的方式不会产生卡顿。

四、参考

https://blog.csdn.net/RSpcc/article/details/109805738

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C是一种高级的编程语言,用于开发各种软件和应用。它的设计目标是提供高效率和高性能的编程环境。 C最初是由贝尔实验室的Dennis Ritchie 在20世纪70年代初开发的。当时,贝尔实验室正在开发一种新的操作系统——Unix,C语言就是为了在Unix上开发高效的系统软件而设计的。 C语言的特点之一是它的可移植性。这意味着一个用C编写的程序可以在不同的操作系统和硬件平台上运行,而不需要进行大量的修改。这得益于C语言对底层硬件操作的支持,并且它的语法和功能设计得足够灵活。 C语言具有简洁而强大的语法,支持各种编程结构,如条件语句、循环语句和函数调用。它还提供了丰富的内置函数和数据类型,以及指针和数组等高级特性,使得开发者可以在编程过程中更加灵活地操作内存和数据。 C语言是许多其他编程语言的基础,包括C++、Java和C#等。它具有较低的学习曲线和广泛的应用领域,在计算机科学、嵌入式系统、游戏开发等领域都得到了广泛的应用。 总之,C语言是一种强大而灵活的编程语言,它的设计目标是提供高效率和高性能的编程环境。无论是初学者还是专业开发者,都可以通过学习和应用C语言来实现他们的编程目标。 ### 回答2: c是英文字母表中的第三个字母,它的发音是/siː/。c也是一种编程语言,被广泛应用于软件开发和科学计算领域。c语言具有简洁、高效、可移植等特点,被许多程序员认为是学习其他高级编程语言的基础。另外,c还可以表示摄氏温度的单位,用于衡量温度。在化学中,c可以代表一种晶体结构,例如钻石常常以c为表示。在数学中,c是代表复数的符号,用于表示实部和虚部的数值。此外,在某些科学领域,c可以代表光速,约为每秒299,792,458米。总的来说,c在不同领域有不同的意义和用途,它在字母表、编程、温度、晶体结构、数学和科学测量等方面都有其特定的含义或属于特定的符号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值