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

本文关键字:检查 服务器 是否 | 更新日期: 2023-09-27 18:28:46

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

如何配置套接字连接超时

现在我正试图创建一个无休止的循环,它将加载到formload事件中,并不断检查服务器是否在侦听。

这是我的代码:

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

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

您可以将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,但其中任何一个都应该让您启动并运行。

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

我不认为您可以多次实例化一个对象。您可能需要放置

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

在while循环之前

为了更好地诊断你的问题,你也可以使用

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

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

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

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

  • 如果它没有在其他线程上运行,很可能你会单击按钮,应用程序将显示为冻结状态,并且UI永远不会更新。。。您需要将其设置为在其他线程上运行。

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

本文展示了在不同线程上运行代码并正确使用InvokeRequired的代码。

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

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

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

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