Jaki jest właściwy sposób zamknięcia gniazda C # w .NET Core 3.1?
Problem
Próbuję poradzić sobie z rozłączeniem dla mojej aplikacji i jakiekolwiek podejście, które wypróbowałem do tej pory, nie powiodło się, próbowałem odłączyć się od strony serwera, próbowałem odłączyć się od strony klienta, ale otrzymuję problemy na obu końcach. aby odłączyć aplikację za pomocą polecenia QUIT bez konieczności zamykania jej za pomocą ikony zamknięcia, ponieważ zgłasza wyjątek
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;
}
}
}
}
To jest błąd, który otrzymałem
Nieobsługiwany wyjątek. System.ObjectDisposedException: nie można uzyskać dostępu do usuniętego obiektu. Nazwa obiektu: „System.Net.Sockets.Socket”. w System.Net.Sockets.Socket.Receive (Byte [] bufor, Int32 offset, Int32 size, SocketFlags socketFlags, SocketError & errorCode) w System.Net.Sockets.Socket.Receive (Byte [] bufor, Int32 offset, Int32 size, SocketFlags socketFlags) w MessengerConsole.Client.clientReceiver () w C: \ Users \ MessengerConsoleAppV2 \ MessengerConsole \ Client.cs: wiersz 42 w System.Threading.ThreadHelper.ThreadStart_Context (Object state) w System.Threading.ExecutionContext.RunInternal wykonanie , Wywołanie zwrotne ContextCallback, stan obiektu) --- Śledzenie końca stosu z poprzedniej lokalizacji, w której został zgłoszony wyjątek --- w System.Threading.ExecutionContext.RunInternal (ExecutionContext ExecutionContext, ContextCallback callback,Stan obiektu) w System.Threading.ThreadHelper.ThreadStart ()
Próbowałem użyć Socket.Disconnect (), Socket.Close (), Socket.Dispose () i wszystkie z nich dają ten sam wynik
EDYTOWAĆ:
dodanie return
w
if(Encoding.Default.GetString(sdata) == "QUIT")
{
serverSocket.Send(sdata, sdata.Length, 0);
serverSocket.Shutdown(SocketShutdown.Both);
serverSocket.Close();
return;
}
Nie powoduje żadnych błędów po stronie serwera, ale klient nadal zgłasza wyjątek dotyczący usuniętego obiektu, do którego uzyskiwany jest dostęp
Nieobsługiwany wyjątek. System.ObjectDisposedException: nie można uzyskać dostępu do usuniętego obiektu. Nazwa obiektu: „System.Net.Sockets.Socket”. w System.Net.Sockets.Socket.Receive (Byte [] bufor, Int32 offset, Int32 size, SocketFlags socketFlags, SocketError & errorCode) w System.Net.Sockets.Socket.Receive (Byte [] bufor, Int32 offset, Int32 size, SocketFlags socketFlags) w MessengerConsole.Client.clientReceiver () w C: \ Users \ MessengerConsoleAppV2 \ MessengerConsole \ Client.cs: wiersz 44 w System.Threading.ThreadHelper.ThreadStart_Context (stan obiektu) w System.Threading.ExecutionContext.RunInternal wykonanie , Wywołanie zwrotne ContextCallback, stan obiektu) --- Śledzenie końca stosu z poprzedniej lokalizacji, w której został zgłoszony wyjątek --- w System.Threading.ExecutionContext.RunInternal (ExecutionContext ExecutionContext, ContextCallback callback,Stan obiektu) w System.Threading.ThreadHelper.ThreadStart ()
Odpowiedzi
We wszystkich miejscach kodu związanego z QUIT
tobą tylko zamykasz i usuwasz gniazdo, ale nie wracasz z nieskończonej pętli obsługującej to gniazdo. Myślę, że ten stos jest wyrzucany przy następnej iteracji, gdy Connected
właściwość jest oceniana w usuniętym gnieździe, spróbuj dodać return
instrukcję po zamknięciu gniazda.