Apa cara yang tepat untuk menutup Soket C # di .NET Core 3.1?

Jan 30 2021

Masalah

Saya mencoba menangani pemutusan sambungan untuk aplikasi saya dan pendekatan apa pun yang telah saya coba sejauh ini gagal, saya mencoba memutuskan sambungan dari sisi server, saya mencoba memutuskan sambungan dari sisi klien tetapi menerima masalah di kedua ujungnya, Apa yang saya coba capai di sini adalah untuk memutuskan sambungan aplikasi melalui perintah QUIT tanpa harus menutupnya dari ikon tutup karena memunculkan pengecualian

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

Ini adalah kesalahan yang saya terima

Pengecualian tidak tertangani. System.ObjectDisposedException: Tidak dapat mengakses objek yang dibuang. Nama objek: 'System.Net.Sockets.Socket'. di System.Net.Sockets.Socket.Receive (Buffer Byte [], offset Int32, ukuran Int32, SocketFlags socketFlags, SocketError & errorCode) di System.Net.Sockets.Socket.Receive (Buffer Byte [], offset Int32, ukuran Int32, SocketFlags socketFlags) di MessengerConsole.Client.clientReceiver () di C: \ Users \ MessengerConsoleAppV2 \ MessengerConsole \ Client.cs: baris 42 di System.Threading.ThreadHelper.ThreadStart_Context (status Objek) di System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext.RunInternal (ExecutionContext executionContext , Callback ContextCallback, Status objek) --- Akhir pelacakan tumpukan dari lokasi sebelumnya tempat pengecualian dilemparkan --- di System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext, ContextCallback callback,Status objek) di System.Threading.ThreadHelper.ThreadStart ()

Saya mencoba menggunakan Socket.Disconnect (), Socket.Close (), Socket.Dispose () dan semuanya menghasilkan hasil yang sama

EDIT:

menambahkan returndalam

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

Tidak menghasilkan error di sisi server, tetapi klien masih memberikan pengecualian dari objek yang dibuang yang sedang diakses

Pengecualian tidak tertangani. System.ObjectDisposedException: Tidak dapat mengakses objek yang dibuang. Nama objek: 'System.Net.Sockets.Socket'. di System.Net.Sockets.Socket.Receive (Buffer Byte [], offset Int32, ukuran Int32, SocketFlags socketFlags, SocketError & errorCode) di System.Net.Sockets.Socket.Receive (Buffer Byte [], offset Int32, ukuran Int32, SocketFlags socketFlags) di MessengerConsole.Client.clientReceiver () di C: \ Users \ MessengerConsoleAppV2 \ MessengerConsole \ Client.cs: baris 44 di System.Threading.ThreadHelper.ThreadStart_Context (status Objek) di System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext.RunInternal (ExecutionContext executionContext.RunInternal (ExecutionContext executionContext , Callback ContextCallback, Status objek) --- Akhir pelacakan tumpukan dari lokasi sebelumnya tempat pengecualian dilemparkan --- di System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext, ContextCallback callback,Status objek) di System.Threading.ThreadHelper.ThreadStart ()

Jawaban

1 AlexeyRumyantsev Jan 30 2021 at 22:00

Di semua tempat kode yang terkait dengan QUITAnda hanya menutup dan membuang soket, tetapi tidak kembali dari loop tak terbatas yang melayani soket ini. Saya pikir tumpukan ini dilemparkan pada iterasi berikutnya ketika Connectedproperti dievaluasi pada soket yang dibuang, coba tambahkan returnpernyataan setelah Anda menutup soket.