GUI中的线程
本文关键字:线程 GUI | 更新日期: 2023-09-27 18:18:43
我有一个做端口扫描的工具,我遇到的问题是,当端点不可达时,GUI冻结,直到它得到某种错误。我试过创建一个线程,但我不太熟悉如何做到这一点。有人能告诉我怎么做吗?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace PortScan
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
timeTextBox.Text = "2000";
}
private void button1_Click(object sender, EventArgs e)
{
ThreadStart threadStart = GetPortStatus;
threadStart.BeginInvoke(null, null);
GetPortStatus();
}
private void GetPortStatus()
{
button1.Enabled = false;
var currentIP = ipaddressTextBox.Text;
int anInteger;
anInteger = Convert.ToInt32(portTextBox.Text);
anInteger = int.Parse(portTextBox.Text);
IPAddress IP = IPAddress.Parse(currentIP);
IPEndPoint EndPoint = new IPEndPoint(IP, anInteger);
Socket query = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//Console.WriteLine("Blocking: {0}", query.Blocking);
//resultsTextBox.Text = currentIP + ":" + anInteger + " is blocked: " + query.Blocking;
//resultsTextBox.Text += Environment.NewLine + currentIP + ":" + anInteger + " is blocked: " + query.Blocking;
try
{
query.Connect(EndPoint);
resultsTextBox.Text += "Connected to " + EndPoint + Environment.NewLine;
}
catch (SocketException i)
{
//Console.WriteLine("Problem connecting to host");
//Console.WriteLine(e.ToString());
resultsTextBox.Text += "Cannot connect to " + EndPoint + ", port maybe blocked" + Environment.NewLine;
query.Close();
button1.Enabled = true;
return;
}
//if (InvokeRequired)
//{
// Invoke(new MethodInvoker(Close));
//}
//else
//{
// Close();
//}
query.Close();
button1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (autoCheckBox.Checked == true)
{
button1_Click(sender, e);
}
else
{
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
如果您正在构建需要在单独线程上执行任务的Windows窗体应用程序,我建议您使用BackgroundWorker
组件。在http://www.dotnetperls.com/backgroundworker上有一个关于如何使用这个组件的优秀教程。
private void button1_Click(object sender, EventArgs e)
{
ThreadStart threadStart = GetPortStatus;
threadStart.BeginInvoke(null, null);
GetPortStatus();
}
应: private void button1_Click(object sender, EventArgs e)
{
ThreadStart threadStart = new ThreadStart(GetPortStatus);
Thread name = new Thread(threadStart);
name.Start();
}
在threadstart构造函数中传递您希望调用的函数的委托。
第一个问题是Socket.Connect()
是一个阻塞方法。在连接成功/被拒绝之前,它不会返回。您可以使用异步方法代替BeginConnect()
和EndConnect()
。但这不是真正的问题,因为您已经在使用一个新线程。
第二个问题是,你不能从主线程以外的其他线程更新你的GUI。
Invoke(new MethodInvoker(() =>
{
... // GUI updates (like your resultsTextBox)
}));
如果你不喜欢Invoke
的东西,你可以使用BackgroundWorker
和它的ReportProgress
方法+ ProgressChanged
事件。
和@Hmm是正确的,因为您不使用新的Thread
对象,该方法是在GUI线程上调用的。但是你需要Invoke
更新,就像我上面描述的。
编辑
顺便说一句,最干净的解决方案是使用AOP (OnGuiThreadAttribute
)来实现关注点分离。