2016-01-28 59 views
0

我有一個可以處理多個客戶端的UDP服務器,現在關於UDP的主要事情是,它是連接少,所以我很驚訝,當我得到以下錯誤:Multiclient udp服務器正確處理錯誤代碼10054

An existing connection was forcibly closed by the remote host.

我很快就學會了,這是因爲我試圖發送到IPEndpoint其關閉。後來我知道這是因爲網絡層會發回一個ICMP消息,說明端口已關閉,並且ICMP消息是導致錯誤的原因。現在顯然我開始尋找這個問題的解決方案,但是,儘管我已經發現了很多關於堆棧溢出的問題,但是我找不到一個有正確答案的問題。 (有些甚至有0個答案)。

當我得到這個錯誤,我不會得到任何東西了,因爲我的BeginReceiveFrom方法是在try部分的異常被拋出之後。然後我把它放在catch部分,但這隻會導致再次拋出相同的錯誤。

這樣的問題,一旦出現錯誤:「現有的連接被強行關閉遠程主機。」被拋出,我不能使用socket了(或者所以在我看來)

,我的問題是:我該如何處理這個異常,所以我的服務器可以繼續運行?

這是我的代碼:

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 > 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); 
     } 
    } 
} 

需要,我希望這個問題能夠得到解決的時候,我很高興來提供額外的信息。

由微軟提供的錯誤描述:

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.

+0

你能縮短代碼嗎?可能需要縮短5倍。現在結束。 – usr

+0

@usr你如何讓我縮短它?刪除評論/文檔? – Vincent

+0

沒有必要證明問題的一切。坦率地說,許多人不會讀這一切。沒有必要看的東西像'公共ip地址地址 { 得到 { 回報this.ServerAddress; } }'。 – usr

回答

0

我已經能夠找到一個解決這個就是下面的代碼:

var sioUdpConnectionReset = -1744830452; 
var inValue = new byte[] { 0 }; 
var outValue = new byte[] { 0 }; 
mServerSocket.IOControl(sioUdpConnectionReset, inValue, outValue); 

通過我的知識簡單地抑制錯誤,我不得不在我的Listen方法中實現它,現在看起來像這樣:

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); 

      var sioUdpConnectionReset = -1744830452; 
      var inValue = new byte[] { 0 }; 
      var outValue = new byte[] { 0 }; 
      mServerSocket.IOControl(sioUdpConnectionReset, inValue, outValue); 

      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 > 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); 
    } 
}