2012-02-17 132 views
1

消息之前要通過對我的一個應用程序,我用一段簡單的代碼,一個TCP連接發送數據:緩衝區被覆蓋,可以讀取

public void Send(byte[] message) 
{ 
    if (socket != null) 
    { 
     if (stream != null) 
     { 
      stream.Write(message, 0, message.Length); 
      if (receiveThread == null) 
      { 
       StartReceiver(); 
      } 
     } 
    } 
} 

插座是TcpClient類的一個實例,並且該流是關聯的流實例。 StartReceiver()啓動一個線程,正如該方法所暗示的那樣,它接收發送給應用程序的數據。

要接收的數據,我使用:

private void ReceiveLoop() 
{ 
    DataReceivedStruct drs; 
    try 
    { 
     for (; ;) 
     { 
      if (stream != null) 
      { 
       drs = new DataReceivedStruct(); 
       drs.stream = stream; 
       drs.waitHandle = are; 
       stream.BeginRead(readBuffer, 0, readBuffer.Length, DataReceived, drs); 
       Console.WriteLine("Waiting to be allowed to continue"); 
       are.WaitOne(); 
       Console.WriteLine("Allowed, continuing loop"); 
      } 
      else 
      { 
       Thread.Sleep(5); 
      } 
     } 
    } 
    catch (SocketException e) 
    { 
     DispatchRaiseException(e); 
    } 
    catch (Exception e) 
    { 
     DispatchRaiseException(e); 
    } 
} 

再次,所用的流是TcpClient類對象的上述流實例。 readBuffer對象是byte[1024]。給BeginRead回調看起來是這樣的:

private void DataReceived(IAsyncResult result) 
{ 
    DataReceivedStruct drs = (DataReceivedStruct)result.AsyncState; 
    NetworkStream used = drs.stream; 
    AutoResetEvent handle = drs.waitHandle; 
    used.EndRead(result); 
    DispatchRaiseReceived(readBuffer); 
    Console.WriteLine("Signalling allowance of continue for loop"); 
    handle.Set(); 
} 

它結束的流讀取動作和傳中readBuffer數據集。

這在原則上起作用。我可以發送和接收來自應用程序的數據。應用程序的接收端只有一個問題。嚮應用程序發送消息時,調用BeginRead函數,之後回調觸發並結束與EndRead的讀取操作,並傳遞數據以供進一步處理。這適用於一次一條消息。但在第一條消息觸發BeginRead後直接發送另一條消息時,它會變得更有趣。接下來會發生的第一條消息的EndRead還沒有發生,所以第一條消息的數據被第二條消息覆蓋,導致數據不正確。

我應該停止使用BeginRead/EndRead,只是使用阻止Read操作來接收數據?還是有可能鎖定流與BeginRead/EndRead,所以第二個消息不會收到,直到第一個消息處理?

+1

而不是使用共享緩衝區('readBuffer'),在'DataReceivedStruct'中聲明它 – 2012-02-17 10:34:20

+0

無關緊要,因爲流仍會覆蓋第二條消息。 – ThaMe90 2012-02-17 10:40:02

+0

不,既然你把它傳遞給'BeginRead' – 2012-02-17 10:47:41

回答

1

國際海事組織,這裏的問題是思考一個循環,因此需要一個繼續旗幟。這不會擴展,因爲它需要每個連接都有一個線程。

什麼你應該做的是:

  • 得到一些數據要發送
  • 開始接收異步(我用ReceiveAsync,但應該的BeginRead工作太)
  • 並退出! (無環)

在回調:

  • 過程的片段(或緩衝它)
  • 開始接收如果必要
  • 和出口!

如果您很樂意替換幾個不同的緩衝區(我使用一個小的微池),您可以交換「進程」,以便您可以繼續與處理並行讀取。但是,你絕對需要讀取不同的緩衝區,以防止覆蓋數據。這通常只需要異常高讀取方案。

如果有幫助,我正在圖書館編寫簡單的TCP客戶機/服務器方案,而不必擔心所有蹩腳的實現細節,我打算釋放作爲開源一次穩定的;包括廣泛的對象池/重用,完全異步使用(使用綁定到完成端口的3.5 API)等。

+0

我知道這是一種與環做事的懶辦法,但我的目標不是去深由於時間限制而成爲整個問題。聽取你的圖書館很有意思,但顯然,這並不是一個可以看到的選項。無論如何,感謝有趣的選擇。 – ThaMe90 2012-02-17 10:36:54

+0

另一方面,我實際上是這樣設計的,因爲我的應用程序可以有多個到其他實例的TCP連接,因此每個連接需要一個線程。如果它是UDP,我可以看到你的建議工作。 – ThaMe90 2012-02-17 10:38:52

+0

@ ThaMe90不知道爲什麼需要一個線程。例如,我目前正在進行的工作;已經使用25k入站連接進行了測試,每個客戶端與一個組中的多個服務器(服務器間的負載平衡客戶端)通信,每個服務器服務於多個TCP綁定;我明確旋轉的線程數:零。 – 2012-02-17 10:40:49