我创建了2个程序。两者都使用间隔设置为250毫秒的计时器。
问题是我的第一个程序没有锁定然后我运行它,第二个锁定没有让我能够点击停止按钮。通过说锁定我的意思是程序运行直到我从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;
}
}
答案 0 :(得分:1)
关于第一个样本:
我想从上下文来看,计时器是一个Windows.Forms.Timer。在elapsed事件中,您正在执行WaitOne(),因此有效地阻止了Messagepump。
作为一种可能的解决方案,用Threading.Timer替换Timer以将I / O与主线程分离。
答案 1 :(得分:1)
由于我们没有足够的信息,我将在这里猜测。我猜测System.Windows.Forms.Timer
中的tmrInterval。如果是这种情况,那么正在发生的事情是,当计时器滴答时,它将被作为一个Windows消息传递(与鼠标点击,击键以及使您的应用程序显示为“未冻结”的所有其他内容的处理方式相同)。 / p>
在第一个应用程序中,你正在做一些花费大量时间的东西 - 打开一个TCP端口,然后等待(大概)大量的毫秒,直到TCP连接或没有,然后几乎立即再次执行它下次计时器滴答作响。你实际上永远不会给应用程序一个机会来响应鼠标点击和击键,因为UI线程正忙着尝试连接某个随机端口。
在第二个应用程序中,您正在做一些相对较快的事情 - 只需在某处发送ping。您可能会在第二个应用程序中看到的是,您的应用程序将“断断续续” - 只需一秒或更短时间就会无响应,同时它会ping您指向的其他任何计算机。它没有被挂起,因为没有给予UI线程很多工作要做。
要解决这两个问题,您应该考虑实施BackgroundWorker。定时器(任何类型)通常不被认为是在.NET中生成后台任务的好方法。