0

I have a UWP (soon to be MacOS also) application that listens for incoming messages. The user can configure which IP Address and Port to listen on. Once the socket connection is listening, the user can also go back into the settings and change the IP Address or Port. I am trying to figure out how to shut down the existing listener and restart it using the new Port / IP Address when the user changes the values. Here is my code that starts the listener. Any help would be appreciated.

   private static Socket iobj_listener;

    public async static Task StartListening()
    {
        try
        {
            Debug.WriteLine("Point 1");
            IPEndPoint localEndPoint = new IPEndPoint(ViewModelObjects.AppSettings.ServerIPAddress, ViewModelObjects.AppSettings.ServerPort);

            // Create a TCP/IP socket.  
            iobj_listener = new Socket(ViewModelObjects.AppSettings.ServerIPAddress.AddressFamily,
                SocketType.Stream, ProtocolType.Tcp);

            // Bind the socket to the local endpoint and listen for incoming connections.  
            iobj_listener.Bind(localEndPoint);
            iobj_listener.Listen(100);
            ViewModelObjects.AppSettings.ListeningOnSocket = true;

            while (true)
            {
                Debug.WriteLine("Point 2");
                // Set the event to nonsignaled state.  
                allDone.Reset();

                // Start an asynchronous socket to listen for connections.  
                Debug.WriteLine("Waiting for a connection on " + ViewModelObjects.AppSettings.ServerIPAddress.ToString() + "...");
                iobj_listener.BeginAccept(
                    new AsyncCallback(AcceptCallback),
                    iobj_listener);

                // Wait until a connection is made before continuing.  
                allDone.WaitOne();
            }

        }
        catch (Exception e)
        {
            Debug.WriteLine(e.ToString());
        }
        finally
        {
            Debug.WriteLine("Point 3");
            ViewModelObjects.AppSettings.ListeningOnSocket = false;
        }
    }
George M Ceaser Jr
  • 1,497
  • 3
  • 23
  • 52
  • Check the link: https://www.c-sharpcorner.com/article/xamarin-android-build-real-life-application-using-tcp47ip-part-three/ – Wendy Zang - MSFT Sep 27 '19 at 08:10
  • This does not appear to have anything to do with changing the port or IP address of the socket. It simply appears that the shutdown process simply shutsdown the computer using this command. System.Diagnostics.Process.Start("Shutdown", "-s -t 10"); – George M Ceaser Jr Sep 27 '19 at 12:06
  • When you want to stop the listener, a simple way is to use `stop` method. For more details, please check the link: https://stackoverflow.com/questions/365370/proper-way-to-stop-tcplistener – Wendy Zang - MSFT Oct 01 '19 at 05:42
  • Wendy, To be clear I am not using the TCPClient object. I an using the System.Net.Sockets Socket object. I Kind of have it working and will post an update shortly. – George M Ceaser Jr Oct 03 '19 at 17:34

1 Answers1

0

SO I could not find any quick answers so had to kind of figure this out on my own. If you see anything wrong with this, please let me know.

First of all I declared an e_Num as follows

public enum ge_SocketStatus
{
    e_NotListening = 0,
    e_Listening = 1,
    e_Restart = 2
}

Then I added a StopListening function to my class that handles all my Socket communications and set the socket status to not listening as follows:

    public static async Task StopListening()
    {
        try
        {
            if (iobj_listener.Connected)
            {
                //Wait till the connection ends or 30 seconds - this is so any last messages can be processed.
                await Task.Delay(30000);

            }
            ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_NotListening;
            iobj_listener.Close(1);

        }
        catch (Exception ex)
        {
            App.AppException(ex);
        }
    }

I then use the value of this enum to know when to end the loop:

 public async static Task StartListening()
    {
        try
        {
            Debug.WriteLine("Point 1");
            IPEndPoint localEndPoint = new     IPEndPoint(ViewModelObjects.AppSettings.ServerIPAddress, ViewModelObjects.AppSettings.ServerPort);

            // Create a TCP/IP socket.  
            iobj_listener = new Socket(ViewModelObjects.AppSettings.ServerIPAddress.AddressFamily,
                SocketType.Stream, ProtocolType.Tcp);

            // Bind the socket to the local endpoint and listen for incoming connections.  
            iobj_listener.Bind(localEndPoint);
            iobj_listener.Listen(100);
            ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_Listening;


            while (ViewModelObjects.AppSettings.SocketStatus == ge_SocketStatus.e_Listening)
            {
                Debug.WriteLine("Point 2");
                // Set the event to nonsignaled state.  
                allDone.Reset();

                // Start an asynchronous socket to listen for connections.  
                Debug.WriteLine("Waiting for a connection on " + ViewModelObjects.AppSettings.ServerIPAddress.ToString() + "...");
                iobj_listener.BeginAccept(
                    new AsyncCallback(AcceptCallback),
                    iobj_listener);

                // Wait until a connection is made before continuing.  
                allDone.WaitOne();
            }

        }
        catch (Exception e)
        {
            Debug.WriteLine(e.ToString());
        }
        finally
        {
            Debug.WriteLine("Point 3");
        }
    }

This line above

while (ViewModelObjects.AppSettings.SocketStatus == ge_SocketStatus.e_Listening)

used to be

while (true)

so the loop would never end.

One gotcha I found is in the AcceptCallback used in the BeginAccept function of my socket. In this code, I also had to detect if the socket was connected because this function is called one last time after the StartListening loop exits. At the point the socket is not connected so trying to do anything with is, such as EndAccept, causes the application to throw an exception. Below you can see where I added the line

if (listener.Connected)

in order to stop the code from crashing after I had closed the connection.

   public static void AcceptCallback(IAsyncResult ar)
    {
        // Signal the main thread to continue.  
        allDone.Set();

        // Get the socket that handles the client request.  
        Socket listener = (Socket)ar.AsyncState;


        //If we have shut down the socket don't do this.  
        if (listener.Connected)
        {
            Socket handler = listener.EndAccept(ar);

            // Create the state object.  
            StateObject state = new StateObject();
            state.workSocket = handler;
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
        }
    }

Once all StopListening function ends and everything from the sockets is disconnected, I can call start listening again and open the socket on a different IPAddress and or Port.

I hope this helps as I could not find a good solution to this.

George M Ceaser Jr
  • 1,497
  • 3
  • 23
  • 52