【问题标题】:constantly check if Server is listening on a given port with C#不断检查服务器是否正在使用 C# 侦听给定端口
【发布时间】:2012-04-07 05:33:49
【问题描述】:

感谢这个答案,我能够确定服务器是否正在侦听给定端口:

How to configure socket connect timeout

现在我正在尝试创建一个无限循环,它将在 form_load 事件中加载,并且会不断检查服务器是否正在监听。

这是我的代码:

            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IAsyncResult result = socket.BeginConnect("192.168.0.131", 1095, null, null);

            bool success = result.AsyncWaitHandle.WaitOne(500, true);

            if (!socket.Connected)
            {label3.Text = "can't use"; socket.Close();}
            else
            {label3.Text = "start action";}

如果我将以下代码放入“on_button_click”事件 - 一切正常(除了 - 我每次想要刷新状态时都必须单击按钮)

当我创建无限循环时 - 我根本没有得到任何结果:

while (true)
        {
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IAsyncResult result = socket.BeginConnect("192.168.0.131", 1095, null, null);

            bool success = result.AsyncWaitHandle.WaitOne(500, true);

            if (!socket.Connected)
            {
                label3.Text = "can't use";
                socket.Close();
            }
            else
            {
                //success = true;
                label3.Text = "start action";
                socket.Close();
            }
        }

我想这与线程有关,但我就是想不通。可能是什么问题?

编辑:

定时器滴答解决方案:

private void Form1_Load_1(object sender, EventArgs e)
        {
            System.Windows.Forms.Timer MyTimer = new System.Windows.Forms.Timer();
            MyTimer.Interval = (200);
            MyTimer.Tick += new EventHandler(MyTimer_Tick);
            MyTimer.Start();
        }

        public void MyTimer_Tick(object sender, EventArgs e)
        {

                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IAsyncResult result = socket.BeginConnect("192.168.0.131", 1095, null, null);

                bool success = result.AsyncWaitHandle.WaitOne(500, true);

                if (!socket.Connected)
                {

                    label3.Text = "can't use";
                    socket.Close();
                    //throw new ApplicationException();
                }
                else
                {
                    //success = true;
                    label3.Text = "start action";
                    socket.Close();
                }   

        }

【问题讨论】:

  • 你的on_button_click方法中有这段代码吗?
  • 它在 button_click 事件中。现在它在 form_load 事件中;)

标签: c# multithreading loops infinite-loop


【解决方案1】:

您可以在表单中添加Timer 对象。在表单加载时启动计时器,并在计时器Tick 事件中,运行您在无限循环中的代码。

注意:不要包含while(true) 循环,只包含循环内的代码。您真的不希望您的 GUI 线程中出现无限循环 :)

编辑
我仍然认为您可能需要考虑重新设计应用行为,但这应该比我之前建议的 Timer 更好

一种更好的计时器方法(应该解决 UI 滞后问题)是为您的 UI 添加一个BackgroundWorker。添加类似这样的DoWork 方法:

void DoWork(object sender, DoWorkEventArgs e)
{
    while(!_bw.CancellationPending)
    {
        // Do your socket connection stuff

        // you can either update some member variables and call
        // the progresschanged method or you can use a BeginIvoke call
        // to update the labels, you CANNOT update the labels in this method
        if (!_bw.CancellationPending)
        {
            // Checking the cancel pending before sleeping so that we don't sleep
            // while a cancel is pending. There are better ways to do this with
            // event handles, but this should get you off and running.
            Thread.Sleep(1000);
        }
    }
    e.Cancel = true;
}

注意:如果您使用的是 .Net 4.0,您可能需要考虑使用任务工厂和取消令牌而不是 BackgroundWorker,但任何一个都应该让您启动并运行。

【讨论】:

  • +1。计时器将自动解决一些线程问题。好主意!
  • 首先 - 谢谢!我已经设法使用 Timer Ticks 使“状态更新”工作(见编辑)。但是,当我使用这种方法时 - 我的程序文学变得无法使用(即冻结,但工作)
  • 这可能是因为等待套接字结果回来。你能把你的滴答间隔调高吗?你真的需要这么多锤击插座吗?检查的目的是什么。在您需要它的操作时只检查套接字会更好吗?
  • 虽然我认为从计时器持续启动异步连接请求并不是最好的解决方案,但我必须 +1 以表示“只需在需要它的操作时检查套接字”。跨度>
  • @Alex 延迟是由于当套接字不可用时,您必须等待完整的 500 毫秒超时才能响应。您真的不应该在 Tick 处理程序中阻塞,它会阻塞 UI。对于这样的事情,您确实需要在工作线程中执行操作。我最初的想法是错误的。听起来您也应该考虑重新设计。关闭侦听器,然后等待它恢复,以便您可以发送更多数据,这似乎是一种不好的模式。如果您发送数据,服务器会收到它,但在关闭侦听器之前,您的应用会发送更多数据会发生什么?
【解决方案2】:

如果在 GUI 线程上执行该循环,它将阻塞 GUI,因为它无法接收用户输入。

您必须在不同的线程上执行代码,然后使用 InvokeBeginInvoke 更新 UI。比如:

Thread t = new Thread(
   o => 
   {
    while (true)
    {
        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IAsyncResult result = socket.BeginConnect("192.168.0.131", 1095, null, null);

        bool success = result.AsyncWaitHandle.WaitOne(500, true);

        if (!socket.Connected)
        {

            label3.BeginInvoke((Action)(() => { label3.Text = "can't use"; }));
            socket.Close();
        }
        else
        {
            //success = true;
            label3.BeginInvoke((Action)(() => { label3.Text = "start action"; }));
            socket.Close();
        }
    }
  });
t.Start();

【讨论】:

  • 帝舵,感谢您的解决方案!它部分解决了我的问题。当我打开服务器监听器时,状态变为“开始操作”半秒,其余时间我看到“无法使用”标签。 ..好吧,至少形式不再冻结。
  • +1 用于不建议计时器/DoEvents 以及从主线程中获取所有连接延迟和 WaitOne() 内容。您可能还需要一个 sleep() 来防止所有可用的套接字卡在 TIME_WAIT 中。 TBH,这个要求无论如何都不好 - 服务器管理员肯定不喜欢持续连接/断开连接的想法!
  • @MartinJames 我的家庭局域网没有任何管理员.. 除了我。此应用程序仅供个人使用。无论如何,感谢您的评论..很多信息要考虑..
【解决方案3】:

我认为你不能多次实例化一个对象。你可能需要把

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

在while循环之前

为了更好地诊断您的问题,您还可以使用

Console.WriteLine("Can't use");
Console.WriteLine("Start action");

查看是否存在线程问题(gui 未更新)

【讨论】:

    【解决方案4】:

    没有足够的代码来告诉我们需要知道的一切,但这是一个开始。

    这个循环是在不同的线程上运行,还是只是在 button_click 事件中?

    • 如果它没有在不同的线程上运行,您可能会单击该按钮,然后应用似乎会冻结,并且 UI 将永远不会更新...您需要将其设置为在不同的线程上运行。

      • 您可以在更新标签后立即抛出 Application.DoEvents() 命令以解冻 UI 并更新标签,但这不是实时代码中要做的事情。您需要为您在生产应用程序中的检查创建一个新线程。 Application.DoEvents 在这种情况下会给你带来问题。
    • 如果它在不同的线程上运行,您可能需要使用 InvokeRequired 来更新表单上的标签。

    This article 显示了在不同线程上运行代码并正确使用 InvokeRequired 的代码。

    【讨论】:

      【解决方案5】:

      关闭 TCP 连接需要一些时间。每次连接到远程服务器并在套接字上调用 close 时,都会发生一次 TCP 握手。

      请参阅本指南http://www.tcpipguide.com/free/t_TCPConnectionTermination-2.htm

      避免以如此高的速率(半秒)打开/关闭套接字。您可以在处于关闭等待状态的远程服务器上构建一长串 TCP 连接,如果这不是您的服务器,则可以将其视为攻击。

      对于失败的连接,这不是问题。

      【讨论】:

        猜你喜欢
        • 2011-02-19
        • 2015-08-28
        • 1970-01-01
        • 1970-01-01
        • 2015-11-29
        • 2015-07-08
        • 1970-01-01
        • 1970-01-01
        • 2011-08-15
        相关资源
        最近更新 更多