当我启动计时器时我的程序锁定,并且我';I’我不知道为什么
本文关键字:为什么 我不知道 计时器 启动 我的 程序 锁定 | 更新日期: 2023-09-27 18:21:20
我已经创建了两个程序。两者都使用间隔设置为250毫秒的计时器。
问题是,我的第一个程序没有锁定,然后我运行它,第二个程序锁定了out,让我可以点击停止按钮。所谓锁,我的意思是程序运行完成它的工作,直到我从VS停止它。
我不明白为什么我不能停止我的第一个程序,而基本相同的方式为其他程序工作。有什么想法吗?
锁定程序:
private void btnScan_Click(object sender, EventArgs e)
{
tmrInterval.Interval = (int)nudInterval.Value;
tmrInterval.Start();
}
private void ScanPort(IPAddress address, int port)
{
using (TcpClient client = new TcpClient())
{
IAsyncResult result = client.BeginConnect(address, port, null, null);
if (result.AsyncWaitHandle.WaitOne((int)nudTimeout.Value, false)) txtDisplay.AppendText("Port: " + port + " is open." + Environment.NewLine);
else txtDisplay.AppendText("Port: " + port + " is closed." + Environment.NewLine);
}
}
private void btnStop_Click(object sender, EventArgs e)
{
tmrInterval.Stop();
}
private void tmrInterval_Tick(object sender, EventArgs e)
{
ScanPort(IPAddress.Parse(txtIP.Text), currentPort);
currentPort++;
if (currentPort == nudTo.Value) tmrInterval.Stop();
}
不锁定的程序:
void tmrPingInterval_Tick(object sender, EventArgs e)
{
if (txtTo.Text == string.Empty) Ping(IPAddress.Parse(ip2str(startIP)));
else
{
if (currentIP >= endIP) tmrPingInterval.Stop();
Ping(IPAddress.Parse(ip2str(currentIP)));
currentIP++;
}
}
private void btnPing_Click(object sender, EventArgs e)
{
if (txtFrom.Text != string.Empty)
{
txtFrom.Enabled = false;
txtTo.Enabled = false;
txtDisplay.Text = string.Empty;
tsslPingCount.Text = string.Empty;
count = 0;
open = 0;
closed = 0;
tmrPingInterval.Interval = int.Parse(nudInterval.Value.ToString());
try
{
startIP = str2ip(txtFrom.Text);
if (txtTo.Text != string.Empty) endIP = str2ip(txtTo.Text);
currentIP = startIP;
tmrPingInterval.Start();
}
catch
{
MessageBox.Show("Input must be in IP format: 100.100.100.100", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
txtFrom.Enabled = true;
txtTo.Enabled = true;
}
}
else MessageBox.Show("IP field cannot be empty!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void btnStop_Click(object sender, EventArgs e)
{
txtFrom.Enabled = true;
txtTo.Enabled = true;
tmrPingInterval.Stop();
}
private void Ping(IPAddress address)
{
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
if (cbDontFragment.Checked) options.DontFragment = true;
else options.DontFragment = false;
string data = string.Empty;
int dataCounter = 0;
options.Ttl = (int)nudTTL.Value;
for (int i = 0; i < nudData.Value; i++)
{
dataCounter++;
if (dataCounter == 10) dataCounter = 0;
data += dataCounter.ToString();
}
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
try
{
PingReply reply = pingSender.Send(address, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
}
else
{
}
}
catch (Exception ex)
{
txtDisplay.SelectedText += Environment.NewLine + ex.Message;
}
}
由于我们没有足够的信息,我将在这里进行猜测。我猜tmrInterval在System.Windows.Forms.Timer
中。如果是这样的话,发生的情况是,当计时器滴答作响时,它会作为一条窗口消息传递(就像处理鼠标点击、击键和其他使应用程序看起来"未冻结"的事情一样)。
在第一个应用程序中,您正在做一些需要大量时间的事情——打开一个TCP端口,然后等待(大概)大量毫秒,直到TCP连接或不连接,然后在下一次计时器计时时几乎立即再次执行。实际上,你从来没有给应用程序一个响应鼠标点击和键击的机会,因为UI线程正忙于连接到某个地方的一些随机端口。
在第二个应用程序中,您正在做一些相对快速的事情——只是在某个地方发送一个ping。你可能会在第二个应用程序中看到,你的应用程序会"卡顿"——当它ping你指向的任何其他机器时,只有一秒钟或更短的时间没有响应。它不会挂起,因为UI线程没有得到那么多工作要做。
要解决这两个问题,您应该考虑实现BackgroundWorker。定时器(任何类型的)通常都不是在.NET中生成后台任务的好方法。
关于第一个样本:
从上下文中,我猜计时器是Windows.Forms.timer。在经过的事件中,您正在执行WaitOne(),因此有效地阻止了Messagepump。
作为一种可能的解决方案,将Timer替换为Threading.Timer,以将I/O与主线程解耦。