C#编写端口扫描器程序

一用C#编写端口扫描器程序

一、创建新项目

1新建一个项目,命名为scanapp
在这里插入图片描述
2放置控件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、端口扫描器

单线程和多线程的区别

什么是线程?

线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,
即不同的线程可以执行同样的函数。

什么是多线程?

多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,
也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

多线程的好处:

可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,
这样就大大提高了程序的效率。

多线程的不利方面:

线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
多线程需要协调和管理,所以需要CPU时间跟踪线程;
线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
线程太多会导致控制太复杂,最终可能造成很多Bug

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.Tasks;
using System.Windows.Forms;

namespace scanapp
{
    public partial class Form1 : Form
    {
        //自定义变量
        private int start;
        private int end;
        private string Addr;
        private int port;
        private bool OK;
        private bool[] done = new bool[65536];


        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //显示端口扫描的范围
            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 textBox1_TextChanged(object sender, EventArgs e)
        {
        }
        private void label4_TextChanged(object sender, EventArgs e)
        {
            label4.Text = textBox2.Text;
        }
        //将输入的结束地址放到进度条的结束位置
        private void label6_TextChanged(object sender, EventArgs e)
        {
            label6.Text = textBox3.Text;
        }
        private void label4_Click(object sender, EventArgs e)
        {
        }

        private void label6_Click(object sender, EventArgs e)
        {
        }
        private void PortScan()
        {
            label4.Text = textBox2.Text;
            label6.Text = textBox3.Text;
            start = Int32.Parse(textBox2.Text);
            end = Int32.Parse(textBox3.Text);
            //检查输入范围合法性
            if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
            {
                listBox1.Items.Add("开始扫描... (可能需要请您等待几分钟)");
                Addr = listBox1.Text;
                for (int i = start; i <= end; i++)
                {
                    port = i;
                    //使用该端口的扫描线程
                    //scanThread = new Thread(new ThreadStart(Scan));
                    //scanThread.Start();
                    //使线程睡眠
                    System.Threading.Thread.Sleep(100);
                    progressBar1.Value = i;
                    label5.Text = i.ToString();
                }
                //未完成时情况
                while (!OK)
                {
                    OK = true;
                    for (int i = start; i <= end; i++)
                    {
                        if (!done[i])
                        {
                            OK = false;
                            break;
                        }
                    }
                    System.Threading.Thread.Sleep(1000);
                }
                listBox1.Items.Add("扫描结束!");
            }
            else
            {
                MessageBox.Show("输入错误,端口范围为[0-65536]");
            }
        }
        private void Scan()
        {
            int portnow = port;
            //创建线程变量
            //Thread Threadnow = scanThread;
            done[portnow] = true;
            //创建TcpClient对象,TcpClient用于为TCP网络服务提供客户端连接
            TcpClient objTCP = null;
            //扫描端口,成功则写入信息
            try
            {
                //用TcpClient对象扫描端口
                objTCP = new TcpClient(Addr, portnow);
                listBox1.Items.Add("端口 " + portnow.ToString() + " 开放!");
            }
            catch
            {
            }
        }


    }
}

运行结果:
在这里插入图片描述

使用单线程的话,程序执行到一半就卡死了,不能移动不能关闭,只能强制终止程序

2.多线程

代码

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 scanapp
{
    public partial class Form1 : Form
    {
        //自定义变量
        private int start;
        private int end;
        private string Addr;
        private int port;
        private Thread scanThread;
        private bool OK;
        private bool[] done = new bool[65536];


        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//设置该属性 为false
        }

        private void button1_Click(object sender, EventArgs e)
        {
            label4_TextChanged(sender, e);
            label6_TextChanged(sender, e);
            label4.Visible = true;
            label5.Visible = true;
            label6.Visible = true;
            Thread process = new Thread(new ThreadStart(PortScan));
            process.Start();
            //显示端口扫描的范围
            progressBar1.Minimum = Int32.Parse(textBox2.Text);
            progressBar1.Maximum = Int32.Parse(textBox3.Text);
            //显示框初始化
            listBox1.Items.Clear();
            listBox1.Items.Add("端口扫描器 v1.0.");
            listBox1.Items.Add("");
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
        }
        private void label4_TextChanged(object sender, EventArgs e)
        {
            label4.Text = textBox2.Text;
        }
        //将输入的结束地址放到进度条的结束位置
        private void label6_TextChanged(object sender, EventArgs e)
        {
            label6.Text = textBox3.Text;
        }
        private void label4_Click(object sender, EventArgs e)
        {
        }

        private void label6_Click(object sender, EventArgs e)
        {
        }
        private void PortScan()
        {
            start = Int32.Parse(textBox2.Text);
            end = Int32.Parse(textBox3.Text);
            //检查输入范围合法性
            if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
            {
                listBox1.Items.Add("开始扫描... (可能需要请您等待几分钟)");
                Addr = listBox1.Text;
                for (int i = start; i <= end; i++)
                {
                    port = i;
                    //使用该端口的扫描线程
                    scanThread = new Thread(new ThreadStart(Scan));
                    scanThread.Start();
                    //使线程睡眠
                    System.Threading.Thread.Sleep(100);
                    progressBar1.Value = i;
                    label5.Text = i.ToString();
                }
                //未完成时情况
                while (!OK)
                {
                    OK = true;
                    for (int i = start; i <= end; i++)
                    {
                        if (!done[i])
                        {
                            OK = false;
                            break;
                        }
                    }
                    System.Threading.Thread.Sleep(1000);
                }
                listBox1.Items.Add("扫描结束!");
            }
            else
            {
                MessageBox.Show("输入错误,端口范围为[0-65536]");
            }
        }
        private void Scan()
        {
            int portnow = port;
            //创建线程变量
            Thread Threadnow = scanThread;
            done[portnow] = true;
            //创建TcpClient对象,TcpClient用于为TCP网络服务提供客户端连接
            TcpClient objTCP = null;
            //扫描端口,成功则写入信息
            try
            {
                //用TcpClient对象扫描端口
                objTCP = new TcpClient(Addr, portnow);
                listBox1.Items.Add("端口 " + portnow.ToString() + " 开放!");
            }
            catch
            {
            }
        }


    }
}

编译运行的时候会出现线程操作无效的问题,
在Form1重载中写上一行代码,问题就解决了,详细参考System.InvalidOperationException:“线程间操作无效: 从不是创建控件“btnSearch”的线程访问它。”
从程序上来说,只有主线程才能访问控件,其他的子线程不能,所以需要一个委托来跨线程访问

public Form1()
{
      InitializeComponent();
      System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//设置该属性 为false
}

在这里插入图片描述
再次运行,运行结果:
在这里插入图片描述

二、总结

了解了单线程和多线程的区别

三、参考资料

System.InvalidOperationException:“线程间操作无效: 从不是创建控件“btnSearch”的线程访问它。”
用C#实现端口扫描器小程序
利用单线程和多线程实现端口扫描器
C# 多线程

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值