Was ist der richtige Weg, um einen C # -Socket in .NET Core 3.1 zu schließen?

Jan 30 2021

Die Angelegenheit

Ich versuche, die Trennung für meine App zu handhaben, und jeder Ansatz, den ich bisher versucht habe, ist fehlgeschlagen. Ich habe versucht, die Verbindung zur Serverseite zu trennen. Ich habe versucht, die Verbindung zur Client-Seite zu trennen, aber auf beiden Seiten Probleme zu erhalten. Was ich hier erreichen möchte, ist um die App über einen QUIT-Befehl zu trennen, ohne sie über das Schließen-Symbol schließen zu müssen, da eine Ausnahme ausgelöst wird

client.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace MessengerConsole
{
class Client
{
    static string username;
    static int port = 8888;
    static IPAddress clientIP;
    static Socket serverSocket;
    static Thread processThread;
    static bool connected = false;

    static string GetIp()
    {
        Console.WriteLine("Type the server ip:");
        String clientIP = Console.ReadLine();
        Console.WriteLine("Client IP: " + clientIP);
        //return clientIP;
        //temp solution
        return "192.168.0.106";
    }

    static void printSession()
    {
        Console.Clear();
        Console.WriteLine("//=====================================================");
        Console.WriteLine("//                       Session Details               ");
        Console.WriteLine("//                    =====================");
        Console.WriteLine("//                    IP: " + clientIP + "\n//                    Time: " + DateTime.Now);
        Console.WriteLine("//=====================================================");
    }
    static void clientReceiver()
    {
        while (true)
        {
            Thread.Sleep(500);
            byte[] buffer = new byte[300];
            int rece = serverSocket.Receive(buffer, 0, buffer.Length, 0);
            Array.Resize(ref buffer, rece);
            if (connected == false)
            {
                Console.WriteLine("[" + DateTime.Now.ToString() + "] " + Encoding.Default.GetString(buffer) + " Connected!");
                connected = true;
            }

            else
            {

                if (Encoding.Default.GetString(buffer) == "QUIT")
                {
                    //Quit
                    Console.WriteLine("Server Shutdown");
                    serverSocket.Shutdown(SocketShutdown.Both);
                    serverSocket.Close();
                   
                }
                else
                {
                    Console.WriteLine("[" + DateTime.Now.ToString() + "] " + Encoding.Default.GetString(buffer));
                }

            }
        }
    }



    public static void StartClient()
    {
        processThread = new Thread(clientReceiver);
        Console.WriteLine("Please enter your name");
        username = Console.ReadLine();
        clientIP = IPAddress.Parse(GetIp());  //Returns IP from GetIP()
        Console.WriteLine("Please enter HostPort");
        //string portString = Console.ReadLine();
        //temp port
        string portString = "80";
        try
        {
            port = Convert.ToInt32(portString);
        }
        catch
        {
            port = 8888;
        }
        try
        {

            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Connect(new IPEndPoint(clientIP, port));
            processThread.Start();
            byte[] name = Encoding.Default.GetBytes(username);
            
            //Send Name
            serverSocket.Send(name);
           // byte[] data = Encoding.Default.GetBytes("<" + username + "> Connected");
            //serverSocket.Send(data, 0, data.Length, 0);
            printSession();
            while (serverSocket.Connected)
            {
                //byte[] sdata = Encoding.Default.GetBytes("<" + username + ">" + Console.ReadLine());
                byte[] sdata = Encoding.Default.GetBytes(Console.ReadLine());
                if(Encoding.Default.GetString(sdata) == "QUIT")
                {
                    serverSocket.Send(sdata, sdata.Length, 0);
                    serverSocket.Shutdown(SocketShutdown.Both);
                    serverSocket.Disconnect(true);
                    serverSocket.Close();
                }

                else
                {
                    serverSocket.Send(sdata, 0, sdata.Length, 0);
                }

            }
        }
        catch (Exception e)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(e.Message);
            Console.ForegroundColor = ConsoleColor.White;
        }

    }
}
}

server.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace MessengerConsole
{
class Server
{

    //Server Socket
    static Socket serverSocket;
    //Client Socket
    static Socket clientSocket;

    //Other Variables
    static int port = 8888;
    static IPAddress serverIP;
    static Thread processThread;
    static string username;
    static bool connected = false;
    //Function returns IP Address
    static string GetIp()
    {
        //Computer Name
        string hostname = Dns.GetHostName();

        /*The IPHostEntry class associates a Domain Name System (DNS) host name with an array of aliases and 
         * an array of matching IP addresses.
         */
        IPHostEntry ipentry = Dns.GetHostEntry(hostname);

        //The Address
        IPAddress[] ipAddress = ipentry.AddressList;

        return ipAddress[ipAddress.Length - 1].ToString();
    }

    static void printSession()
    {
        Console.Clear();
        Console.WriteLine("//=====================================================");
        Console.WriteLine("//                       Session Details               ");
        Console.WriteLine("//                    =====================");
        Console.WriteLine("//                    You are hosting the server");
        Console.WriteLine("//                    Time: " + DateTime.Now);
        Console.WriteLine("//=====================================================");
    }
    //Receive
    static void serverReciever()
    {
        while (true)
        {
            Thread.Sleep(500);
            byte[] buffer = new byte[300];
            int rece = clientSocket.Receive(buffer, 0, buffer.Length, 0);
            Array.Resize(ref buffer, rece);

            if (connected == false)
            {
                Console.WriteLine("[" + DateTime.Now.ToString() + "] " + Encoding.Default.GetString(buffer) + " Connected!");
                connected = true;
            }

            else
            {
                if(Encoding.Default.GetString(buffer) == "QUIT")
                {
                    //Quit
                    Console.WriteLine("Client disconnected from the chat");
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Close();
                }
                else
                {
                    Console.WriteLine("[" + DateTime.Now.ToString() + "] " + Encoding.Default.GetString(buffer));
                }

            }
        }
    }



    public static void StartServer()
    {
        //Thread
        processThread = new Thread(serverReciever);

        //Display
        Console.WriteLine("Your Local Ip is " + GetIp());
        Console.WriteLine("Please enter your name");
        username = Console.ReadLine();
        Console.WriteLine("Please enter HostPort");
        //  string portString = Console.ReadLine();
        //temp solution
        string portString = "80";
        try
        {
            port = Convert.ToInt32(portString);
        }
        catch
        {
            port = 8888;
        }

        try
        {
            //GetIp returns string
            serverIP = IPAddress.Parse(GetIp());
            //TCP Socket
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Bind(new IPEndPoint(serverIP, port));
            serverSocket.Listen(0);

            //Server Socket listening for client requests
            clientSocket = serverSocket.Accept();
            printSession();
            processThread.Start();
            byte[] name = Encoding.Default.GetBytes(username);
            clientSocket.Send(name);
            while (true)
            {
                byte[] sdata = Encoding.Default.GetBytes(Console.ReadLine());
                clientSocket.Send(sdata, 0, sdata.Length, 0);
            }
        }
        catch
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("Server already open!");
            Console.ForegroundColor = ConsoleColor.White;
        }
    }
}
}

Dies ist der Fehler, den ich erhalten habe

Unbehandelte Ausnahme. System.ObjectDisposedException: Auf ein entsorgtes Objekt kann nicht zugegriffen werden. Objektname: 'System.Net.Sockets.Socket'. bei System.Net.Sockets.Socket.Receive (Byte [] -Puffer, Int32-Offset, Int32-Größe, SocketFlags-SocketFlags, SocketError & errorCode) bei System.Net.Sockets.Socket.Receive (Byte [] -Puffer, Int32-Offset, Int32-Größe, SocketFlags socketFlags) bei MessengerConsole.Client.clientReceiver () in C: \ Users \ MessengerConsoleAppV2 \ MessengerConsole \ Client.cs: Zeile 42 bei System.Threading.ThreadHelper.ThreadStart_Context (Objektstatus) bei System.Threading.ExecutionContext , ContextCallback-Rückruf, Objektstatus) --- Ende der Stapelverfolgung vom vorherigen Speicherort, an dem die Ausnahme ausgelöst wurde --- bei System.Threading.ExecutionContext.RunInternal (ExecutionContext-Ausführungskontext, ContextCallback-Rückruf,Objektstatus) bei System.Threading.ThreadHelper.ThreadStart ()

Ich habe versucht, Socket.Disconnect (), Socket.Close (), Socket.Dispose () zu verwenden, und alle liefern das gleiche Ergebnis

BEARBEITEN:

Hinzufügen returnin der

if(Encoding.Default.GetString(sdata) == "QUIT")
            {
                serverSocket.Send(sdata, sdata.Length, 0);
                serverSocket.Shutdown(SocketShutdown.Both);
                serverSocket.Close();
                return;
            }

Auf der Serverseite treten keine Fehler auf, aber der Client löst immer noch die Ausnahme des bereitgestellten Objekts aus, auf das zugegriffen wird

Unbehandelte Ausnahme. System.ObjectDisposedException: Auf ein entsorgtes Objekt kann nicht zugegriffen werden. Objektname: 'System.Net.Sockets.Socket'. bei System.Net.Sockets.Socket.Receive (Byte [] -Puffer, Int32-Offset, Int32-Größe, SocketFlags-SocketFlags, SocketError & errorCode) bei System.Net.Sockets.Socket.Receive (Byte [] -Puffer, Int32-Offset, Int32-Größe, SocketFlags socketFlags) bei MessengerConsole.Client.clientReceiver () in C: \ Users \ MessengerConsoleAppV2 \ MessengerConsole \ Client.cs: Zeile 44 bei System.Threading.ThreadHelper.ThreadStart_Context (Objektstatus) bei System.Threading.ExecutionContext , ContextCallback-Rückruf, Objektstatus) --- Ende der Stapelverfolgung vom vorherigen Speicherort, an dem die Ausnahme ausgelöst wurde --- bei System.Threading.ExecutionContext.RunInternal (ExecutionContext ExecutionContext, ContextCallback-Rückruf,Objektstatus) bei System.Threading.ThreadHelper.ThreadStart ()

Antworten

1 AlexeyRumyantsev Jan 30 2021 at 22:00

An allen Stellen des Codes, die QUITSie betreffen, schließen und entsorgen Sie nur den Socket, kehren aber nicht von der Endlosschleife zurück, die diesen Socket bedient. Ich denke, dieser Stapel wird bei der nächsten Iteration geworfen, wenn die ConnectedEigenschaft für den entsorgten Socket ausgewertet wird. Versuchen Sie, eine returnAnweisung hinzuzufügen , nachdem Sie den Socket geschlossen haben.