2010-09-02 34 views
0

我写这是要作为一个TCP监听一个客户端的应用程序。客户端是一个java applet,并且会定期连接到监听器,发送一些数据然后等待响应。异步插座,强制断开和重用

为低于TCPSERVER类的代码已经在很大程度上从由更有见识计算器构件响应于一个不同的问题提供了一个示例解除。

一切都很顺利,直到我发现在测试一些东西,wasnt在任何界面文件我有提到。在服务器响应客户端之后,它必须断开客户端并再次开始收听。

我首先想到的是从调用()内送出数据断开(),但是这会导致从一个地方到ReceiveCompleted()的调用和关于已经被设置在插座一个讨厌的例外。

这方面的要求与代码设计,我很容易地实现,我会在重用为后续连接插座时遇到任何问题?

sealed class TcpServer : IDisposable 
    { 
     #region Fields 

     private const int SocketBufferSize = 1024; 

     private readonly TcpListener tcpListener; 

     private Socket connectedSocket; 
     private bool disposed = false; 

     #endregion Fields 

     #region Constructors 

     public TcpServer(int port) 
     { 
      tcpListener = new TcpListener(IPAddress.Any, port); 
      tcpListener.Start(); 
      tcpListener.BeginAcceptSocket(EndAcceptSocket, tcpListener); 
     } 

     ~TcpServer() 
     { 
      Dispose(false); 
     } 

     #endregion Constructors 

     #region Events 

     public event EventHandler<DataReceivedEventArgs> DataReceived; 

     public event EventHandler<IPEndPointEventArgs> SocketConnected; 

     public event EventHandler<IPEndPointEventArgs> SocketDisconnected; 

     #endregion Events 

     #region Methods 

     public void Dispose() 
     { 
      Dispose(true); 
     } 

     public void SendData(byte[] data) 
     { 
      if (connectedSocket == null) 
      { 
       return; 
      } 
      connectedSocket.Send(data); 
     } 

     private void BeginReceiveAsync(Socket sock, SocketAsyncEventArgs e) 
     { 
      if (!sock.ReceiveAsync(e)) 
      { 
       ReceiveCompleted(sock, e); 
      } 
     } 

     private void Connected(Socket socket) 
     { 
      var endPoint = (IPEndPoint)socket.RemoteEndPoint; 

      connectedSocket = socket; 

      OnSocketConnected(endPoint); 
     } 

     private void Disconnect(Socket socket) 
     { 
      var endPoint = (IPEndPoint)socket.RemoteEndPoint; 

      socket.Close(); 

      connectedSocket = null; 

      OnSocketDisconnected(endPoint); 

      tcpListener.BeginAcceptSocket(EndAcceptSocket, tcpListener); 
     } 

     private void Dispose(bool disposing) 
     { 
      if (this.disposed == false) 
      { 
       if (disposing) 
       { 
        try 
        { 
         if (tcpListener != null) 
         { 
          this.disposed = true; 
          tcpListener.Stop(); 
         } 
        } 
        catch (Exception ex) 
        { 
         TraceLog.Error("TcpServer: tcpListener.Stop(): {0}", ex.Message); 
        } 

        try 
        { 
         if (connectedSocket != null) 
         { 
          connectedSocket.Close(); 
          connectedSocket = null; 
         } 
        } 
        catch (SocketException ex) 
        { 
         TraceLog.Error("TcpServer: connectedSocket.Close(): {0}", ex); 
        } 
       } 
       this.disposed = true; 
      } 
     } 

     private void EndAcceptSocket(IAsyncResult asyncResult) 
     { 
      var listener = (TcpListener)asyncResult.AsyncState; 

      if (disposed) 
      { 
       return; 
      } 

      try 
      { 
       Socket sock = listener.EndAcceptSocket(asyncResult); 
       Connected(sock); 

       var e = new SocketAsyncEventArgs(); 
       e.Completed += ReceiveCompleted; 
       e.SetBuffer(new byte[SocketBufferSize], 0, SocketBufferSize); 
       BeginReceiveAsync(sock, e); 
      } 
      catch (SocketException ex) 
      { 
       TraceLog.Error("TcpServer.EndAcceptSocket: {0}", ex.Message); 
      } 
      catch (Exception ex) 
      { 
       TraceLog.Error("TcpServer.EndAcceptSocket: {0}", ex.Message); 
      } 
     } 

     private void OnDataReceived(byte[] data, IPEndPoint ipEndPoint) 
     { 
      if (DataReceived != null) 
      { 
       DataReceived(this, new DataReceivedEventArgs(data, ipEndPoint)); 
      } 
     } 

     private void OnSocketConnected(IPEndPoint ipEndPoint) 
     { 
      if (SocketConnected != null) 
      { 
       SocketConnected(this, new IPEndPointEventArgs(ipEndPoint)); 
      } 
     } 

     private void OnSocketDisconnected(IPEndPoint ipEndPoint) 
     { 
      if (SocketDisconnected != null) 
      { 
       SocketDisconnected(this, new IPEndPointEventArgs(ipEndPoint)); 
      } 
     } 

     private void ReceiveCompleted(object sender, SocketAsyncEventArgs e) 
     { 
      var sock = (Socket)sender; 

      if (!sock.Connected) 
      { 
       Disconnect(sock); 
      } 

      try 
      { 
       int size = e.BytesTransferred; 
       if (size == 0) 
       { 
        Disconnect(sock); 
       } 
       else 
       { 
        var buf = new byte[size]; 
        Array.Copy(e.Buffer, buf, size); 
        ReceiveData(buf, (IPEndPoint)sock.RemoteEndPoint); 
        BeginReceiveAsync(sock, e); 
       } 
      } 
      catch (SocketException ex) 
      { 
       TraceLog.Error("TcpServer: ReceiveCompleted: {0}", ex.Message); 
      } 
      catch (Exception ex) 
      { 
       TraceLog.Error("TcpServer: ReceiveCompleted: {0}", ex.Message); 
      } 
     } 

     private void ReceiveData(byte[] data, IPEndPoint endPoint) 
     { 
      OnDataReceived(data, endPoint); 
     } 

     #endregion Methods 
    } 

回答

1

每当我写,围绕System.Net.Sockets.Socket包装代码,我发现自己不断增加的try/catch子句SocketException和的ObjectDisposedException。在大多数情况下,ObjectDisposedException可以简单地被忽略,因为它在99%的情况下表明客户端已经简单地断开连接。

至少这是我在.NET中的Socket API是如何工作的印象。尝试在这里和那里添加一些异常处理程序,并看看它是如何发生的。在任何情况下,你的Disconnect方法不应该做更多的事情是这样的:

public void Disconnect() 
    { 
     try 
     { 
      connectedSocket.Shutdown(SocketShutdown.Both); 
     } 
     catch (Exception) 
     { 
      // Ignore the exception. The client probably already disconnected. 
     } 

     connectedSocket.Dispose(); // This is safe; a double dispose will simply be ignored. 
    } 

我希望揭示了这个问题的一些轻......