问题
I am creating a server for a game that handles multiple clients over UDP
using the asynchronous methods, and am specifically working on clean disconnect logic. When a client hard crashes (their program is closed without proper disconnect logic) the readCallback
on the server throws the SocketException
An existing connection was forcibly closed by the remote host
which makes sense, however when the read is triggered the next time on the loop in read
it crashes despite the exception being handled in the callback.
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();
}
Two exceptions are thrown, one of which I believe is being caught:
Exception thrown: 'System.Net.Sockets.SocketException' in System.dll System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host at System.Net.Sockets.Socket.EndReceiveFrom(IAsyncResult asyncResult, EndPoint& endPoint) at CardCatacombs.Utilities.Networking.UDPNetworkConnection.readCallback(IAsyncResult ar) in C:\Users\kayas\Desktop\Practicum\Source\CardCatacombs\CardCatacombs\Utilities\Networking\UDPNetworkConnection.cs:line 424
Exception thrown: 'System.Net.Sockets.SocketException' in System.dll System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host at System.Net.Sockets.Socket.DoBeginReceiveFrom(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, EndPoint endPointSnapshot, SocketAddress socketAddress, OverlappedAsyncResult asyncResult)
I would like to be able to cleanly handle a client crash and continue running since there are other clients connected to the server.
回答1:
From this forum thread, it seems that the UDP socket is also receiving ICMP messages and throwing exceptions when they are received. If the port is no longer listening (after the hard crash), the ICMP message causes the 'forcibly closed' exception.
If not wanted, this exception can be disabled using the following code when creating the UdpClient, explained in the above post:
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
);
来源:https://stackoverflow.com/questions/38191968/c-sharp-udp-an-existing-connection-was-forcibly-closed-by-the-remote-host