2013-05-13 51 views
1

有一個異步服務器的代碼。客戶端發送Header - 數據塊+數據塊的大小。如何使用NetworkStream.BeginRead讀取所有請求的數據?

服務器先異步讀取頭然後數據塊。

我需要讀取數據塊後,運行BeginRead for Header讀取部分,使線程異步。

問題:

當我DataCallBack中,管線:

INT bytesRead = ns.EndRead(結果);

我得到的不是所有的緩衝區我問

mc.Client.GetStream()的BeginRead閱讀(mc.DataBuffer,0,大小,新的AsyncCallback(DataCallBack),MC)。

如果客戶端發送1MB的數據,我可以得到不同數量的「bytesRead」。

問題:

如何給力 「的BeginRead」 從連接讀取的所有數據。它應該導致標題 - 數據的新循環。

MyClient - 簡單地通過TcpClient封裝;

CODE:

public void DoAcceptTcpClientCallback(IAsyncResult ar) 
    { 
     TcpListener listener = (TcpListener)ar.AsyncState; 
     TcpClient client = listener.EndAcceptTcpClient(ar); 
     client.NoDelay = false; 
     // client.ReceiveBufferSize = 1024*1024; 
     listener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), listener); 
     MyClient mc = new MyClient(client); 
     ContinueRead(0,mc); 
    } 

    public void ContinueRead(int size, MyClient mc) 
    { 
     if (size != 0) 
     { 
      mc.DataBuffer = new byte[size]; 
      mc.Client.GetStream().BeginRead(mc.DataBuffer, 0, size, new AsyncCallback(DataCallBack), mc); 
     } 
     mc.Client.GetStream().BeginRead(mc.HeaderBuffer, 0, 4, new AsyncCallback(HeaderCallBack), mc); 

    } 

    private void HeaderCallBack(IAsyncResult result) 
    { 
     MyClient mc = (MyClient)result.AsyncState; 
     NetworkStream ns = mc.Stream; 
     int bytesRead = ns.EndRead(result); 
     if (bytesRead == 0) 
      throw new Exception(); 
     mc.TotalLengs = BitConverter.ToInt32(mc.HeaderBuffer, 0); 
     ContinueRead(mc.TotalLengs, mc); 

    } 
    private void DataCallBack(IAsyncResult result) 
    { 
     MyClient mc = (MyClient)result.AsyncState; 
     NetworkStream ns = mc.Stream; 
     int bytesRead = ns.EndRead(result); 
     if (bytesRead == 0) 
      throw new Exception(); 

糟糕的代碼 - 讓異步閱讀 - SYNC

 while (bytesRead < mc.TotalLengs) 
     { 
      bytesRead += ns.Read(mc.DataBuffer, bytesRead, mc.TotalLengs - bytesRead); 
     } 

END糟糕的代碼

 ContinueRead(0, mc); 
     ProcessPacket(mc.DataBuffer, mc.IP); 
    } 

回答

4

「如果客戶端發送1MB的數據,我可以得到不同數量的」bytesRead「。」

是的......這只是TCP如何工作。你不能改變這一點。 TCP保證數據包的命令,而不是它們如何分組。數據包傳輸路線上的硬件和流量條件決定了數據如何分組(或未分組)。

「如何強制」BeginRead「讀取連接中的所有數據。」

TCP不知道有多少數據正在發送。就它而言,連接只是無盡的字節流;因此無法讀取「所有數據」,因爲數據無法結束(從其角度來看)。 TCP也沒有關於您的應用程序的「完整信息」的概念。程序員可以自己決定開發一個協議,它允許您的應用程序知道何時發送了所有數據。

如果您希望獲得一定數量的字節,請保持EndRead()返回的值的運行總和,並在該魔數被命中時停止。

+0

對於我想要在C++中做什麼的模擬。套接字的「recv」有一個選項,如「msg_waitall」。它只是讀取您告訴讀取的字節數。直到它讀取它將不會返回控制。 – user2377299 2013-05-13 14:26:10

+0

很酷。我所說的一切仍然適用;甚至是C++ recv()函數。就像我所說的,你可以跟蹤EndRead()(或其同步等價物)的返回值所接收到的總字節數。考慮到這一點,你可以編寫自己的.net版本的recv()。如果你想要「內置」更高級別的網絡功能,那麼從第三方公司購買**庫**。 – 2013-05-13 14:35:33

+0

heh。我需要最高的性能。但每次調用BeginRead都沒有效果,因爲我需要每次都從系統核心線程切換到我的編程線程 - 這需要時間...所以在C++中,我需要一個BeginRead,在C#中需要很多... – user2377299 2013-05-13 15:06:49

相關問題