2014-01-29 32 views
2

我試圖學習如何在C#中創建異步tcp服務器,並且我的代碼有一個小問題。試圖創建一個異步tcp服務器

I tried to modify this code

,這就是我所做的:

public class ClientContext 
{ 
    public TcpClient client { get; set; } 
    public NetworkStream stream { get; set; } 
    public byte[] buffer { get; set; } 
    public string message { get; set; } 
    // public MemoryStream message = new MemoryStream(); 

    public ClientContext() 
    { 
     buffer = new byte[14]; 
     message = ""; 
    } 
} 

public class TCPServer 
{ 

    public TCPServer() 
    { 
     // Setup the server side 
     TcpListener listener = new TcpListener (new IPEndPoint (IPAddress.Parse("127.0.0.1"), 14000)); 
     listener.Start(); 
     // Server side ok, wait for client to connect 
     listener.BeginAcceptTcpClient (OnClientAccepted, listener); 

     Console.WriteLine ("Press enter to exit..."); 
     Console.ReadLine(); 
     listener.Stop(); 
    } 

    private void OnClientAccepted (IAsyncResult ar) 
    { 
     // A client connected 
     TcpListener listener = (TcpListener)ar.AsyncState; 

     if (listener == null) 
      return; 

     try { 
      // Create a new client context to store connection infos about dat client 
      ClientContext context = new ClientContext(); 
      context.client = listener.EndAcceptTcpClient (ar); 
      context.stream = context.client.GetStream(); 
      // The client is now ready, read what it has to say 
      context.stream.BeginRead (context.buffer, 0, context.buffer.Length, OnClientRead, context); 
     } finally { 
      listener.BeginAcceptTcpClient (OnClientAccepted, listener); 
     } 
    } 

    private void OnClientRead (IAsyncResult ar) 
    { 
     // The client wants to say something 
     ClientContext context = (ClientContext)ar.AsyncState; 
     context.message = ""; 

     if (context == null) 
      return; 

     try { 
      // Read what it says 
      if(context.stream.CanRead) { 

       do { 

        context.stream.Read (context.buffer, 0, context.buffer.Length); 
        context.message += Encoding.ASCII.GetString (context.buffer); 
        //length -= context.message.Length; 

       } while (context.stream.DataAvailable); // && length < readBuffer.Length 

       OnMessageReceived(context); 
      } 

     } catch (Exception) { 
      context.client.Close(); 
      context.stream.Close(); 
      context = null; 
     } finally { 
      // If we are still connected to the client, read what it has to say... 
      if (context != null) 
       context.stream.BeginRead (context.buffer, 0, context.buffer.Length, OnClientRead, context); 
     } 

    } 

    private void OnMessageReceived (ClientContext context) 
    { 
     // Display what the client said 
     Console.WriteLine ("Message reçue : " + context.message); 
    } 
} 

的問題是:我有一個發送50客戶端的 「Hello World!」消息到服務器,並且服務器只打印25/26「hello world !!」在控制檯。我使用SocketSniff來查看套接字,並且我看到服務器套接字接收到50「hello world !!」,所以我必須使用我的代碼失敗,但是什麼?

你們有什麼想法嗎?

回答

1
context.stream.Read (context.buffer, 0, context.buffer.Length); 
context.message += Encoding.ASCII.GetString (context.buffer); 

這裏你不檢查從Stream.Read回報。 Read可能會在緩衝區中放置一個字節,但是您將解碼整個緩衝區,其中包含以前Read調用的剩餘字節。這必須是:

int bytesRead = context.stream.Read (context.buffer, 0, context.buffer.Length); 
context.message += Encoding.ASCII.GetString (context.buffer, 0, bytesRead); 

但是你遇到的問題是不同的。你正在做一個危險的混合同步和異步...結果。 您不應該在BeginRead回調中發出同步讀取!相反,你必須調用EndRead

int bytesRead = context.stream.EndRead(ar); 
context.message += Encoding.ASCII.GetString (context.buffer, 0, bytesRead); 
OnMessageReceived(context); 
context.stream.BeginRead (context.buffer, 0, context.buffer.Length, OnClientRead, context); 

有沒有必要檢查DataAvailable也不CanRead

+0

首先感謝您的快速回答。我根據你所說的改變了我的代碼,並修復了它。非常感謝。 – Devnunux