2011-08-24 51 views
6

我目前正在測試一個託管的c#網絡庫,我已經寫過,並且遇到了偶爾的問題。這個問題表現爲networkstream.write()中的一個非常一致的(總是在30ms內)5000ms的塊,可能是所有發送操作的1%。這是在一個測試環境中,全部在本地運行,每次使用完全相同的數據包大小(2MB)。在客戶端我連寫下面給所連接的NetworkStream:Networkstream.Write()阻止問題

tcpClientNetworkStream.Write(headerBytes, 0, headerBytes.Length); 
tcpClientNetworkStream.Write(dataBytes, 0, dataBytes.Length); 

和在服務器端我使用異步讀取等待數據。一旦數據出現,我會在tcpClientNetworkStream.DataAvailable上使用while循環,直到收到所有數據。

我知道networkstream.write()可以阻止緩衝區是否已滿,但如果這是問題,我想不出在服務器端更快地清除它們的方法(發送和接收緩衝區大小爲默認值在8192字節)。該塊如此一致的事實似乎很奇怪。我的第一個想法可能是某種形式的Thread.Sleep,但是做一個完整的項目搜索沒有顯示。如果有人能夠幫助解決這個問題,將不勝感激。

馬克

編輯補充:這似乎使問題消失一劈爲以下(雖然有相關的性能,因爲打的BlockCopy):

byte[] bytesToSend = new byte[headerBytes.Length + dataBytes.Length]; 
Buffer.BlockCopy(headerBytes, 0, bytesToSend, 0, headerBytes.Length); 
Buffer.BlockCopy(dataBytes, 0, bytesToSend, headerBytes.Length, dataBytes.Length); 
tcpClientNetworkStream.Write(bytesToSend, 0, bytesToSend.Length); 

編輯ADD2 :我也通過在兩者之間使用兩個線程信號的異步寫入來再現問題。目前唯一的解決方案就是上述編輯中的單寫操作。

編輯爲add3:好的,另一個可能的修復如下。我仍然很想知道爲什麼連續寫作會偶爾「阻塞」它的方式。

BufferedStream sendStream = new BufferedStream(tcpClientNetworkStream); 
sendStream.Write(bytesToSend, 0, bytesToSend.Length); 
sendStream.Write(packet.PacketData, 0, packet.PacketData.Length); 
sendStream.Flush(); 

編輯ADD4:經過進一步的廣泛測試的解決方案「編輯到ADD3」不會使問題消失,它只是降低了發生於約0.1%的發送。好得多,但很難解決。正如PaulF所建議的那樣,我將用下一個阻塞讀取替換異步讀取,以查看是否對它進行排序。

+0

請發出更多的代碼,比如dataBytes從哪裏來?它被緩衝在什麼地方? – EKS

+0

我將一個數據包對象傳遞給包含上述NetworkStream.Write()方法的SendPacket()方法。一旦在SendPacket()之外創建了這個數據包對象,它就包含'headerBytes'和'dataBytes'的字節數組。 – MarcF

+0

我很想知道如果在服務器端使用同步(阻塞)讀取,問題是否仍然存在。 – PaulF

回答

2

好的,沒有具體的答案這個問題,所以我會盡我所能提供一個小小的結論。我最好的猜測是,這個問題最初是由於我填充的tcp緩衝區比我清理它的速度更快。如果緩衝區已滿,在嘗試添加更多數據之前會有一些未知的等待時間。當在同一臺機器內發送和接收數據時,這個問題可能最爲明顯。請記住,.net中的默認讀取緩衝區大小僅爲8192字節,因此如果要寫入更大的區塊,可能考慮將此讀取緩衝區大小增加到更大的值,例如512000字節。然而,這本身導致其他問題,由於大對象堆等,但這是潛在的討論到一個不同的問題。