不断检查服务器是否正在使用C#侦听给定端口

时间:2012-03-22 15:56:38

标签: c# multithreading loops infinite-loop

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

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();
                }   

        }

5 个答案:

答案 0 :(得分:2)

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

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

EDIT
我仍然认为您可能需要考虑重新设计应用程序行为,但这应该比我之前建议的计时器更好

更好的方法(应该处理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 :(得分:1)

如果在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();

答案 2 :(得分:0)

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

这个循环是在另一个线程上运行,还是只是在button_click事件中?

  • 如果它没有在另一个线程上运行,可能你会点击该按钮,应用程序将显示为冻结,并且UI永远不会更新......你需要将其设置为运行在不同的主题。

    • 您可以在更新标签后立即抛出Application.DoEvents()命令以解冻UI并更新标签,但这不是实时代码中的事情。您需要为生产应用中的签入创建新线程。此场景中的Application.DoEvents会导致问题。
  • 如果它在另一个线程上运行,您可能需要使用InvokeRequired来更新表单上的标签。

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

答案 3 :(得分:0)

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

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
在while循环之前

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

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

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

答案 4 :(得分:0)

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

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

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

对于失败的连接,这不是一个真正的问题。