C#单线程和多线程端口扫描器详解
作者:一只特立独行的猪
这篇文章主要为大家详细介绍了C#单线程和多线程端口扫描器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
本文为大家分享了C#单线程和多线程端口扫描器,供大家参考,具体内容如下
一、项目创建以及页面设计
(一)项目新建
1.选择Windows窗体项目应用(.Net Framework)->下一步:
2.项目命名以及合适的存储位置,选择创建
(二)页面设计
1.点开工具箱,需要4个Label,一个Button,一个Progress,4个TextBox
2.横向拉伸TextBox
(1)点击三角形
(2)勾选Multiline
后拉伸
(3)设置控件的名称和唯一标志
设置唯一标志
修改显示名称
(4)页面设计如下
(5)设置消息显示界面的 TextBox 不可编辑:找到 Enabled 属性,参数设为 False 。
二、单线程实现端口扫描
(一)代码实现
1.双击按钮btnShow
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 cqjtuWindowsFormsApp { 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 label1_Click(object sender, EventArgs e) { } private void label2_Click(object sender, EventArgs e) { } private void label4_Click(object sender, EventArgs e) { } private void button1_Click(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 { //未扫描到,则会抛出错误 } } } }
(二)运行结果
1.启动项目
2.输入相关信息
3.扫描结果
三、多线程实现端口扫描
(一)程序实现
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 cqjtuWindowsFormsApp { 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 label1_Click(object sender, EventArgs e) { } private void label2_Click(object sender, EventArgs e) { } private void label4_Click(object sender, EventArgs e) { } private void button1_Click(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 { //未扫描到,则会抛出错误 } } } }
(二)运行结果
1.启动项目
2.输入相关信息
3.扫描结果
可以发现多线程扫描只需要十几秒,而单线程需要几分钟,明显多线程比单线程更快些
四、总结
可以发现多线程能够有更好的CPU使用率,可以使程序设计更简单,明显可以看见多线程拥有更快的程序响应速度。
五、参考资料
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。