关闭.NETCore3.1中的C#套接字的正确方法是什么?
问题 我正在尝试处理我的应用程序的断开连接,无论我尝试了什么方法都失败了,我尝试从服务器端断开连接,我尝试从客户端断开连接,但两端都有问题,我在这里试图实现的是通过QUIT命令断开应用程序的连接,而不必在抛出异常时从close图标关闭它 client.cs关闭.NETCore3.1中的C#套接字的正确方法是什么?,c#,.net,sockets,.net-core,asp.net-core-3.1,C#,.net,Sockets,.net Core,Asp.net Core 3.1,问题 我正在尝试处理我的应用程序的断开连接,无论我尝试了什么方法都失败了,我尝试从服务器端断开连接,我尝试从客户端断开连接,但两端都有问题,我在这里试图实现的是通过QUIT命令断开应用程序的连接,而不必在抛出异常时从close图标关闭它 client.cs using System; using System.Collections.Generic; using System.Text; using System.Net; using System.Net.Sockets; using Syst
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;
}
}
}
}
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”。在MessengerConsole.Client.clientReceiver()的System.Net.Sockets.Socket.Receive(Byte[]buffer,Int32 offset,Int32 size,SocketFlags,SocketFlags,SocketError&errorCode)的System.Net.Sockets.Socket.Receive(Byte[]buffer,Int32 offset,Int32 size,SocketFlags,SocketFlags)中在C:\Users\Messenger控制台Appv2\Messenger控制台\Client.cs中:System.Threading.ThreadHelper.ThreadStart\u上下文(对象状态)的第42行,位于System.Threading.ExecutionContext.RunInternal(ExecutionContext ExecutionContext,ContextCallback回调,对象状态)---在System.Threading.ThreadHelper.ThreadStart()上的System.Threading.ExecutionContext.RunInternal(ExecutionContext ExecutionContext,ContextCallback回调,对象状态)上引发异常的上一个位置的堆栈结束跟踪
我尝试使用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;
}
结果服务器端没有错误,但客户端仍然抛出正在访问的已释放对象的异常
未处理的异常。System.ObjectDisposedException:无法访问已处置的对象。
对象名称:“System.Net.Sockets.Socket”。
位于System.Net.Sockets.Socket.Receive(字节[]缓冲区、Int32偏移量、Int32大小、SocketFlags、SocketError和errorCode)
位于System.Net.Sockets.Socket.Receive(字节[]缓冲区、Int32偏移量、Int32大小、SocketFlags和SocketFlags)
在C:\Users\Messenger ConsoleEAppv2\Messenger Console\Client.cs中的Messenger Console.Client.clientReceiver()处:第44行
位于System.Threading.ThreadHelper.ThreadStart\u上下文(对象状态)
位于System.Threading.ExecutionContext.RunInternal(ExecutionContext ExecutionContext,ContextCallback回调,对象状态)
---来自引发异常的上一个位置的堆栈结束跟踪---
位于System.Threading.ExecutionContext.RunInternal(ExecutionContext ExecutionContext,ContextCallback回调,对象状态)
位于System.Threading.ThreadHelper.ThreadStart()处
在与
QUIT
相关的所有代码位置中,您只能关闭和处理套接字,而不能从服务于此套接字的无限循环返回。我认为在下一次迭代中,当对disposed socket上的Connected
属性求值时,会抛出此堆栈。请尝试在关闭socket后添加return
语句。当我在serverSocket.close()下面添加“return”时,您在下一次迭代中抛出的堆栈是正确的;它工作得很好,但客户端仍有一个错误。receiver()仍在等待从服务器接收数据,并且再次抛出相同的异常(我将在回答中编辑它)。您正在使用SocketShutdown。两者都是,这是优雅地停止网络对话的一种不好的方式。在这里检查答案也许会有帮助。或者您可以在try catch块中包装套接字操作,catchObjectDisposedException
并在那里添加return
,以静默方式放弃异常。ObjectDisposedException是一个临时修复,我将您的解释标记为答案