我正在为一个游戏创建一个服务器,该服务器使用异步方法通过 UDP
处理多个客户端,并且专门致力于干净的断开连接逻辑。当客户端硬崩溃时(他们的程序在没有适当的断开连接逻辑的情况下关闭)服务器上的 readCallback
抛出 SocketException
An existing connection was forcibly closed by the remote host
这是有道理的,但是当下次在 read
的循环中触发读取时,尽管在回调中处理了异常,它还是崩溃了。
private void connectedState()
{
while (connected)
{
//reset the trigger to non-signaled
readDone.Reset();
read(socket);
//block on reading data
readDone.WaitOne();
}
}
private void read(Socket sock)
{
// Creates an IpEndPoint to capture the identity of the sending host.
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint senderRemote = sender;
// Create the state object.
StateObject state = new StateObject();
state.workSocket = sock;
//crashes after an exception is caught within the callback
sock.BeginReceiveFrom(state.buffer, 0, StateObject.MESSAGE_SIZE, SocketFlags.None, ref senderRemote, new AsyncCallback(readCallback), state);
}
private void readCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket sock = state.workSocket;
EndPoint senderRemote = new IPEndPoint(IPAddress.Any, 0);
try
{
// Read data from the client socket.
int bytesRead = sock.EndReceiveFrom(ar, ref senderRemote);
if (bytesRead <= 0)
{
//handle disconnect logic
}
else
{
//handle the message received
}
}
catch (SocketException se)
{
Console.WriteLine(se.ToString());
}
// Signal the read thread to continue
readDone.Set();
}
抛出了两个异常,我相信其中一个被捕获了:
抛出异常:System.dll 中的“System.Net.Sockets.SocketException” System.Net.Sockets.SocketException (0x80004005): 现有连接被远程主机强行关闭 在 System.Net.Sockets.Socket.EndReceiveFrom(IAsyncResult asyncResult,EndPoint&endPoint) 在 CardCatacombs.Utilities.Networking.UDPNetworkConnection.readCallback(IAsyncResult ar) 在 C:\Users\kayas\Desktop\Practicum\Source\CardCatacombs\CardCatacombs\Utilities\Networking\UDPNetworkConnection.cs:line 424
抛出异常:System.dll 中的“System.Net.Sockets.SocketException” System.Net.Sockets.SocketException (0x80004005): 现有连接被远程主机强行关闭 在 System.Net.Sockets.Socket.DoBeginReceiveFrom(Byte[] 缓冲区,Int32 偏移量,Int32 大小,SocketFlags socketFlags,EndPoint endPointSnapshot,SocketAddress socketAddress,OverlappedAsyncResult asyncResult)
我希望能够干净地处理客户端崩溃并继续运行,因为还有其他客户端连接到服务器。
最佳答案
来自 this forum thread ,似乎UDP套接字也在接收ICMP消息并在接收时抛出异常。如果端口不再监听(在硬崩溃之后),ICMP 消息会导致“强制关闭”异常。
如果不需要,可以在创建 UdpClient 时使用以下代码禁用此异常,如上文所述:
public const int SIO_UDP_CONNRESET = -1744830452;
var client = new UdpClient(endpoint);
client.Client.IOControl(
(IOControlCode)SIO_UDP_CONNRESET,
new byte[] { 0, 0, 0, 0 },
null
);
对于dotnet core用户,由于这个“Socket.IOControl”是Windows特有的控制代码,不支持其他平台,我们会得到以下异常:
Unhandled exception. System.PlatformNotSupportedException: Socket.IOControl handles Windows-specific control codes and is not supported on this platform.
为了更好的兼容性,我们应该检查当前的平台:
using System.Runtime.InterosServices;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
//...
}
关于C# UDP 现有连接被远程主机强行关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38191968/