我一直在努力與此,並找不到我的代碼未能正確讀取我寫的TCP服務器正確的原因。我正在使用TcpClient
類和其GetStream()
方法,但某些功能無法按預期工作。操作無限期地阻塞(最後一次讀操作沒有按預期超時),或者數據被裁剪(出於某種原因,讀操作返回0並退出循環,可能服務器響應速度不夠快)。這三個企圖實現這種功能:什麼是正確的方式從NET讀取NetworkStream
// this will break from the loop without getting the entire 4804 bytes from the server
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
bytes = 0;
if (stm.DataAvailable)
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
// this will block forever. It reads everything but freezes when data is exhausted
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
// inserting a sleep inside the loop will make everything work perfectly
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
Thread.Sleep(20);
bytes = 0;
if (stm.DataAvailable)
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
最後一個「作品」,但它確實看起來難看把一個硬編碼的睡眠考慮到插座已經支持讀取超時循環內!我是否需要在NetworkStream
的TcpClient
上設置一些房產?問題是否存在於服務器中?服務器不關閉連接,這取決於客戶端。以上內容也在UI線程環境(測試程序)內部運行,可能與此有關......
有人知道如何正確使用NetworkStream.Read
來讀取數據,直到沒有更多的數據可用?我想我希望的是像舊的Win32 winsock的超時屬性... ReadTimeout
等,嘗試讀取,直到達到超時,然後返回0 ...但它有時似乎回到0時數據應提供(或在路上..如果能提供?讀返回0)無限期最後一次讀取數據時不可用,它再塊...
是的,我不知所措!
要小心。您嘗試(和答案)中的代碼不會關閉客戶端或流,如果重複調用,會導致資源泄漏,並帶來很大的後果。你應該使用(var stm = client.GetStream())'使用(var client = new System.Net.Sockets.TcpClient(ip,port)) '然後用花括號括住剩餘的方法。這將保證在方法退出時,不管什麼原因,連接都關閉,資源被回收。 –
你見過TcpClient類的代碼嗎?我建議看看它...如果您仍想在端點上回答,則不應關閉流或tcpclient(如果我沒有弄錯,會關閉流)。但是我使用的實際代碼是不同的,我會將其挖掘出來並更新這裏的答案。 – Loudenvier
感謝您的建議。我發現[TCPClient.cs](http://referencesource.microsoft.com/#system/net/System/Net/Sockets/TCPClient.cs)。事實上,關閉或處理'TCPClient'會處理流。實際上,當一個程序做出數千個連接時沒有多少注意(其他原因很糟糕),我確實發現連接失敗。爲什麼要在這裏偏離通常的IDisposable模式?實現IDisposable容易出錯,'使用()'它很容易和安全。 –