title: Multiclient udp server handling error code 10054 properly
body: <p>I've got an UDP server which can handle multiple clients, Now the main thing about UDP is that it is connection less so i was quite suprised when i got the following error:</p>
  
  <blockquote>
    <p>An existing connection was forcibly closed by the remote host.</p>
  </blockquote>
  
  <p>I quickly learned this was because I was trying to send to an IPEndpoint which was closed. Later I learned this was because the network layer would send back an ICMP message saying the port was closed and the ICMP message is why the error is thrown. Now obviously I started to look for solutions for this problem but, although I've found many questions about this on stack overflow, I could not find one with a correct answer. (some even have 0 answers).</p>
  
  <p>When I got this error i wouldn't receive anything anymore because my <code>BeginReceiveFrom</code> method was in the try part after the exception was thrown. I then placed it in the catch part as well but this would simply result in the same error being thrown again.</p>
  
  <p>so the problem, once the error: "An existing connection was forcibly closed by the remote host." is thrown I cannot use the socket anymore (or so it seems to me)</p>
  
  <p>and my question is: how do i handle this exception so my server can keep running?</p>
  
  <p>This is my code:</p>
  
  <pre><code>public void Listen()
  {
      if (mDisposing == true)
      {
          throw new ObjectDisposedException(null, "This instance is already disposed");
      }
  
      if (mListening == false)
      {
          try
          {
              mListening = true;
              ServerEndPoint = new IPEndPoint(ServerAddress, Port);
              mServerSocket = new Socket(ServerAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
              mServerSocket.Bind(ServerEndPoint);
  
              if (ServerAddress.AddressFamily == AddressFamily.InterNetworkV6)
              {
                  OperatingSystem os = Environment.OSVersion;
                  Version version = os.Version;
  
                  // NOTE: Windows Vista or higher have one IP stack for IPv4 and IPv6
                  // Therefore they can be combined and used as one socket for IPv6
                  // The socket must then accept both IPv4 and IPv6 connections.
                  if (version.Major &gt; 5)
                  {
                      // NOTE: IPV6_V6ONLY socket option is equivalent to 27 in the winsock snippet below
                      // This is available in Framework 4.0. A lower version can implement (SocketOptionName)27
                      mServerSocket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
                  }
              }
  
              var ipeSender = new IPEndPoint(IPAddress.Any, 0);
              var endPointSender = (EndPoint)ipeSender;
              mServerSocket.BeginReceiveFrom(mByteData, 0, mByteData.Length, SocketFlags.None, ref endPointSender, new AsyncCallback(OnDataReceived), null);
          }
          catch (Exception exception)
          {
              mListening = false;
              DoError(exception);
          }
      }
      else
      {
          var ipeSender = new IPEndPoint(IPAddress.Any, 0);
          var endPointSender = (EndPoint)ipeSender;
          mServerSocket.BeginReceiveFrom(mByteData, 0, mByteData.Length, SocketFlags.None, ref endPointSender, new AsyncCallback(OnDataReceived), null);
      }
  }
  
  public void Close()
  {
      if (mDisposing == true)
      {
          throw new ObjectDisposedException(null, "This instance is already disposed");
      }
  
      if (mListening == true)
      {
          mListening = false;
  
          try
          {
              foreach (ClientInformation client in mClients)
              {
                  Disconnect(client.ID);
              }
  
              if (mServerSocket != null)
              {
                  mServerSocket.Close();
              }
          }
          catch (Exception exception)
          {
              DoError(exception);
          }
      }
  }
  
  private void WaitForData()
  {
      if (mListening == true)
      {
          try
          {
              var ipeSender = new IPEndPoint(IPAddress.Any, 0);
              var endPointSender = (EndPoint)ipeSender;
              mServerSocket.BeginReceiveFrom(mByteData, 0, mByteData.Length, SocketFlags.None, ref endPointSender, new AsyncCallback(OnDataReceived), null);
          }
          catch (Exception exception)
          {
              DoError(exception);
          }
      }
  }
  
  private void OnDataReceived(IAsyncResult asyncResult)
  {
      if (mListening == true)
      {
          try
          {
              IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
              EndPoint remoteEndPoint = ipeSender;
  
              int iRx = mServerSocket.EndReceiveFrom(asyncResult, ref remoteEndPoint);
              var clientInfo = new ClientInformation(remoteEndPoint);
  
              mClients.Add(clientInfo);
  
              var chars = new byte[iRx];
              Buffer.BlockCopy(mByteData, 0, chars, 0, iRx);
              WaitForData();
              DoReceived(clientInfo, chars);
          }
          catch (Exception exception)
          {
              WaitForData();
              DoError(exception);
          }
      }
  }
  
  public void Send(string remoteEndPoint, byte[] data)
  {
      if (mListening == true)
      {
          var clientInfo = ActiveConnections.Find(remoteEndPoint);
          if (clientInfo != null)
          {
              try
              {
                  lock (LockSend)
                  {
                      clientInfo.DataOut = data;
                      mServerSocket.BeginSendTo(
                          clientInfo.DataOut,
                          0,
                          clientInfo.DataOut.Length,
                          SocketFlags.None,
                          clientInfo.RemoteEndPoint,
                          new AsyncCallback(OnDataSent),
                          clientInfo);
                  }
              }
              catch (Exception exception)
              {
                  DoError(exception);
              }
          }
          else
          {
              mLogger.ErrorFormat("Trying to send to client {0} which does not exist", remoteEndPoint);
          }
      }
  }
  
  private void OnDataSent(IAsyncResult asyncResult)
  {
      if (mListening == true)
      {
          var clientInfo = (ClientInformation)asyncResult.AsyncState;
          try
          {
              lock (LockSend)
              {
                  int iRx = mServerSocket.EndSendTo(asyncResult);
                  if (iRx == clientInfo.DataOut.Length)
                  {
                      byte[] chars = new byte[iRx];
                      Buffer.BlockCopy(clientInfo.DataOut, 0, chars, 0, iRx);
                      DoSent(clientInfo, chars);
                  }
              }
          }
          catch (Exception exception)
          {
              DoError(exception);
          }
      }
  }
  </code></pre>
  
  <p>I am happy to provide extra information when needed and am hoping this problem can be resolved.</p>
  
  <p>The error description as provided by microsoft:</p>
  
  <blockquote>
    <p>WSAECONNRESET 10054 Connection reset by peer. An existing connection
    was forcibly closed by the remote host. This normally results if the
    peer application on the remote host is suddenly stopped, the host is
    rebooted, the host or remote network interface is disabled, or the
    remote host uses a hard close (see setsockopt for more information on
    the SO_LINGER option on the remote socket). This error may also result
    if a connection was broken due to keep-alive activity detecting a
    failure while one or more operations are in progress. Operations that
    were in progress fail with WSAENETRESET. Subsequent operations fail
    with WSAECONNRESET.</p>
  </blockquote>