Xamarin Forms如何更改套接字连接的端口或IP地址

Xamarin Forms How to change Port or IPAddress of socket connection

我有一个 UWP(很快也会成为 MacOS)应用程序来侦听传入的消息。用户可以配置要监听的 IP 地址和端口。一旦套接字连接正在侦听,用户还可以返回设置并更改 IP 地址或端口。我试图弄清楚如何在用户更改值时关闭现有侦听器并使用新的端口/IP 地址重新启动它。这是我启动侦听器的代码。任何帮助将不胜感激。

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

所以我找不到任何快速答案,所以不得不自己想办法。如果您发现其中有任何问题,请告诉我。

首先我声明了一个e_Num如下

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

然后我向我的 class 添加了一个 StopListening 函数来处理我所有的套接字通信并将套接字状态设置为不监听,如下所示:

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

然后我使用这个枚举的值来知道何时结束循环:

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

上面这一行

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

曾经是

while (true)

所以循环永远不会结束。

我发现的一个陷阱是在我的套接字的 BeginAccept 函数中使用的 AcceptCallback。在此代码中,我还必须检测套接字是否已连接,因为在 StartListening 循环退出后最后一次调用此函数。此时套接字未连接,因此尝试使用 is 执行任何操作(例如 EndAccept)会导致应用程序抛出异常。下面你可以看到我在哪里添加了行

if (listener.Connected)

为了防止代码在我关闭连接后崩溃。

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

一旦所有 StopListening 函数结束并且来自套接字的所有内容都断开连接,我可以再次调用开始侦听并在不同的 IP 地址和/或端口上打开套接字。

希望这对我有所帮助,因为我找不到好的解决方案。