Alex
Alex

Reputation: 5227

constantly check if Server is listening on a given port with C#

thanks to this answer I was able to determine if Server is listening on a given port or not:

How to configure socket connect timeout

now I'm trying to create an endless loop, which will be loaded on form_load event and will be constantly checking if server is listening.

here is my code:

            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";}

If I put following code into "on_button_click" event - everything works fine (except for - I have to click the button every single time I want to refresh status)

and when I create endless loop - I'm not getting any results at all:

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

I guess it has something to do with threading but I just can't figure it out. What might be the problem?

Edit:

timer tick solution:

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

        }

Upvotes: 1

Views: 2583

Answers (5)

pstrjds
pstrjds

Reputation: 17428

You can add a Timer object to your form. Start the timer on the form load, and in the timer Tick event, run your code that you have in the infinite loop.

Note: DO NOT include the while(true) loop, just the code inside the loop. You really don't want an infinite loop in your GUI thread :)

EDIT
I still think you may need to consider a redesign of the app behavior, but this should be better than the Timer I suggested earlier

A somewhat better approach to the Timer (which should take care of the UI lag issue) would be for you to add a BackgroundWorker to your UI. Add a DoWork method similar to this:

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

Note: If you were using .Net 4.0, you may want to consider using the task factory and a cancellation token rather than the BackgroundWorker, but either one should get you up and running.

Upvotes: 2

Reactgular
Reactgular

Reputation: 54771

It takes time for a TCP connection to be closed. Each time you connect to the remote server and call close on the socket a TCP handshaking takes place.

See this guide http://www.tcpipguide.com/free/t_TCPConnectionTermination-2.htm

Avoid, opening/closing sockets at such a high rate (half a second). You could build a long list of TCP connections on the remote server that are in a close wait condition, and if this isn't your server then it could be thought of as an attack.

For failed connections, this isn't really a problem.

Upvotes: 0

David
David

Reputation: 73564

There's not enough code to tell everything we need to know, but here's a start.

Is this loop running on a different thread, or is it just there in the button_click event?

  • If it's not running on a different thread, likely you'll click the button and the app will appear to freeze, and the UI will never get updated... You need to set this up to run on a different thread.

    • You can throw an Application.DoEvents() command immediately after updating the label to unfreeze the UI and update the label, but this isn't something to do in live code. You'll want to create a new thread for your check in a production app. Application.DoEvents in this scenario would cause you problems.
  • If it IS running on a different thread, you probably need to use InvokeRequired to update the labels on the form.

This article shows code for running code on a different thread and using InvokeRequired properly.

Upvotes: 0

Lectrode
Lectrode

Reputation: 412

I don't think you can instantiate an object more than once. You may need to put

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

before the while loop

To better diagnose your problem you could also use

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

to see if there is a threading issue or not (with the gui not updating)

Upvotes: 0

Tudor
Tudor

Reputation: 62439

If that loop is executed on the GUI thread it will block the GUI because it becomes unable to receive user input.

You have to execute the code on a different thread and then update the UI using Invoke or BeginInvoke. Something like:

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

Upvotes: 1

Related Questions