2013-12-11 61 views
1

我在寫一個基本的TCP/IP服務器來接收來自現有客戶端的消息。目前,我能夠接收單緩衝和多緩衝消息。客戶端發送一組多條消息時會出現問題。與其將每個消息作爲單個通信發送,它希望打開流,並且在流再次關閉之前,將集合中的所有消息一個接一個地發送。我在下面的編輯片段編碼此:NetworkStream.DataAvailable更新緩慢

private void AcceptMessage(IAsyncResult ar) 
{ 
    String receivedMessage = ""; 

    // Only run if the server is listening. Otherwise, an exception will be thrown. 
    if (isListening) 
    { 
     ASCIIEncoding encoder = new ASCIIEncoding(); 
     try 
     { 
      TcpListener listener = (TcpListener)ar.AsyncState; 
      using (TcpClient client = listener.EndAcceptTcpClient(ar)) 
      using (NetworkStream stream = client.GetStream()) 
      { 
       int bytesRead; 
       int totalBytes = 0; 
       stream.ReadTimeout = ReadTimeout; 
       do 
       { 
        byte[] receivedBytes = new byte[BufferSize]; 
        StringBuilder message = new StringBuilder(); 
        bytesRead = 0; 
        do 
        { 
         try 
         { 
          if (stream.CanRead) 
          bytesRead = stream.Read(receivedBytes, 0, BufferSize); 
         } 
         catch (...Exception Handling...) 

         if (bytesRead == 0) 
          break; 

         message.Append(encoder.GetString(receivedBytes, 0, bytesRead)); 
         totalBytes += bytesRead; 
        } while (bytesRead == BufferSize);  // Allow for multiple buffers in a single message 
        byte[] ack = encoder.GetBytes(GetAck(message.ToString(), ackNak, status, statusMessage)); 
        stream.Write(ack, 0, ack.Length); 
        ...Message Processing... 
       } while (stream.DataAvailable);   // Allow for multiple messages       
      } 
     } 
     catch (...Error Handling...) 
     finally { ...Cleanup...} 
    } 
} 

這個問題是在第二while (stream.DataAvailable);當檢查時,DataAvailable發送一組消息的時候顯示的是假的,但如果我把一個破下一行它會表現真實。換句話說,在數據可用之前它正在檢查數據是否可用。我可以通過在檢查是否有更多消息之前增加一秒延遲來解決此問題,但在100個案例中有99個,這將是不必要的延遲。由於客戶端一次只能發送一條消息(或一組消息),因此在繁忙時間內可能會增加大量時間來接收消息。

有沒有更好的方法來確定是否有更多的消息掛起(沒有客戶端修改)?謝謝!

編輯

我更改了代碼以包含建議。我添加了暫停,並將第一張支票從stream.DataAvailable更改爲bytesRead == BufferSize。我無法訪問客戶端軟件,因此我無法添加EOM傳輸。我也無法保證多個消息是以單個流還是多個單獨的流發送。我還沒有想出如何判斷是否有更多的消息未決。我不能讓流打開,因爲這阻止了下一次傳輸。

我標記爲Elgonzo作爲答案,因爲他幫助我的問題的大部分方面。它仍然沒有回答如何判斷是否有消息掛起,這可能是不可能的,但我的經理認爲,一旦連接打開,我們應該將其作爲專用連接打開。這是有效的,因爲我們的聽衆只能通過具有一致流量的內部安全網絡與單個設備進行通信。如果在一段時間內沒有活動,我們將增加暫停時間。

+0

有幾個,如果任何正確的使用可用,這不是其中之一。您應該阻止並閱讀,直到您有所需,或使用異步或非阻塞I/O同上。 – EJP

回答

2

數據是否可用,服務器端數據進入的速度(和週期性)不僅取決於客戶端的時間/行爲,還取決於網絡/網絡的速度和延遲因素,互聯網連接(其本身取決於許多未知因素)。

因此,您不能在外部while循環中使用stream.DataAvailable來檢查是否會有更多數據進入。您可能必須在NetworkStream上設置ReadTimeout以瞭解客戶端何時完成/斷開連接。

此外,當客戶端即將結束其連接時,最好實現由客戶端發送的特定信號/消息,而不僅僅依賴於超時。這可以幫助您排除問題,如果問題不清楚問題是由服務器還是客戶端造成的,或者問題是由網絡連接問題引起的。在回答這個問題

實現細節(儘管不同應用場景的方法是一樣的):Reading from closed NetworkStream doesn't cause any exception

另外,即使你內心while循環可能會失敗的糟糕/慢速網絡連接,並可能會離開你與從客戶端部分接收到的消息,只是因爲stream.DataAvailable可能會在下一個數據包(繼續當前消息)之前暫時爲假...

+0

謝謝你的建議。不幸的是,我沒有訪問客戶端代碼的權限,所以我不能添加EndMessage標記。然而,我確實設置了讀取超時,並檢查是否填充了緩衝區,以便確定整個消息是否已發送,或者還有更多消息來臨。不幸的是,我仍然沒有可靠的方法來確定第二條消息是否會在同一個流上傳輸。謝謝你的建議。 – Tim

+0

不幸的是,如果客戶發送的信息不包含這些信息,那麼您無法可靠地判斷客戶是否會發送更多日期。我忘了在我的回答中提到,你也不能完全依靠* Read()*返回'0'(a-ka連接關閉),因爲無論服務器套接字和客戶端套接字之間的代理或時髦事情是否可能儘管客戶端已經很長時間了,但仍然保持服務器端連接長時間處於打開狀態。 – elgonzo

0

我會建議開始自己的線程,它在後臺運行,並只是從數據流中讀取數據,如果有數據可用。如果收到數據,只需收集數據,直到收到完整的消息(應該用定義的字節或字節序列表示),然後再發出事件。在我看來,這應該有助於避免這個問題。