当我启动计时器时我的程序锁定,并且我';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;
        }
    }

当我启动计时器时我的程序锁定,并且我';I’我不知道为什么

由于我们没有足够的信息,我将在这里进行猜测。我猜tmrInterval在System.Windows.Forms.Timer中。如果是这样的话,发生的情况是,当计时器滴答作响时,它会作为一条窗口消息传递(就像处理鼠标点击、击键和其他使应用程序看起来"未冻结"的事情一样)。

在第一个应用程序中,您正在做一些需要大量时间的事情——打开一个TCP端口,然后等待(大概)大量毫秒,直到TCP连接或不连接,然后在下一次计时器计时时几乎立即再次执行。实际上,你从来没有给应用程序一个响应鼠标点击和键击的机会,因为UI线程正忙于连接到某个地方的一些随机端口。

在第二个应用程序中,您正在做一些相对快速的事情——只是在某个地方发送一个ping。你可能会在第二个应用程序中看到,你的应用程序会"卡顿"——当它ping你指向的任何其他机器时,只有一秒钟或更短的时间没有响应。它不会挂起,因为UI线程没有得到那么多工作要做。

要解决这两个问题,您应该考虑实现BackgroundWorker。定时器(任何类型的)通常都不是在.NET中生成后台任务的好方法。

关于第一个样本:

从上下文中,我猜计时器是Windows.Forms.timer。在经过的事件中,您正在执行WaitOne(),因此有效地阻止了Messagepump。

作为一种可能的解决方案,将Timer替换为Threading.Timer,以将I/O与主线程解耦。