.NET Core 3.1에서 C # 소켓을 닫는 적절한 방법은 무엇입니까?

Jan 30 2021

문제

나는 내 앱에 대한 연결 끊기를 처리하려고하는데 지금까지 시도한 접근 방식이 실패했습니다. 서버 측에서 연결을 끊으려고 시도했지만 클라이언트 측에서 연결을 끊으려고했지만 양쪽에서 문제가 발생했습니다. 여기서 달성하려는 것은 예외가 발생할 때 닫기 아이콘에서 닫을 필요없이 QUIT 명령을 통해 앱 연결을 끊으려면

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

이것은 내가받은 오류입니다.

처리되지 않은 예외입니다. System.ObjectDisposedException : 삭제 된 개체에 액세스 할 수 없습니다. 개체 이름 : 'System.Net.Sockets.Socket'. System.Net.Sockets.Socket.Receive (Byte [] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, SocketError & errorCode) at System.Net.Sockets.Socket.Receive (Byte [] buffer, Int32 offset, Int32 size, SocketFlags socketFlags) at MessengerConsole.Client.clientReceiver () in C : \ Users \ MessengerConsoleAppV2 \ MessengerConsole \ Client.cs : line 42 at System.Threading.ThreadHelper.ThreadStart_Context (Object state) at System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext) , ContextCallback callback, Object state) --- 예외가 발생한 이전 위치의 스택 추적 끝 --- at System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext, ContextCallback callback,개체 상태) System.Threading.ThreadHelper.ThreadStart ()

Socket.Disconnect (), Socket.Close (), Socket.Dispose () 사용을 시도했는데 모두 동일한 결과를 산출합니다.

편집하다:

추가 return

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

서버 측에서 오류가 발생하지 않지만 클라이언트는 여전히 액세스중인 삭제 된 개체의 예외를 throw합니다.

처리되지 않은 예외입니다. System.ObjectDisposedException : 삭제 된 개체에 액세스 할 수 없습니다. 개체 이름 : 'System.Net.Sockets.Socket'. System.Net.Sockets.Socket.Receive (Byte [] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, SocketError & errorCode) at System.Net.Sockets.Socket.Receive (Byte [] buffer, Int32 offset, Int32 size, SocketFlags socketFlags) at MessengerConsole.Client.clientReceiver () in C : \ Users \ MessengerConsoleAppV2 \ MessengerConsole \ Client.cs : line 44 at System.Threading.ThreadHelper.ThreadStart_Context (Object state) at System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext) , ContextCallback callback, Object state) --- 예외가 발생한 이전 위치의 스택 추적 끝 --- at System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext, ContextCallback callback,개체 상태) System.Threading.ThreadHelper.ThreadStart ()

답변

1 AlexeyRumyantsev Jan 30 2021 at 22:00

QUIT소켓을 닫고 폐기하는 것과 관련된 모든 코드 위치 에서이 소켓을 제공하는 무한 루프에서 반환되지 않습니다. 이 스택은 Connected속성이 폐기 된 소켓에서 평가 될 때 다음 반복에서 던져 진다고 생각 return합니다. 소켓을 닫은 후 문을 추가해보십시오 .