Я боролся с этим и не могу найти причину, по которой мой код не умеет правильно читать с TCP-сервера, который я также написал. Я использую класс TcpClient
и его метод GetStream()
, но что-то не работает должным образом. Либо операция блокируется бесконечно (последняя операция чтения не отключается, как ожидалось), либо данные обрезаны (по какой-либо причине операция чтения возвращает 0 и выходит из цикла, возможно, сервер не отвечает достаточно быстро). Это три попытки реализовать эту функцию:
// 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());
}
Последний "работает", но он, безусловно, выглядит уродливым, чтобы помещать жесткий цикл внутри цикла, учитывая, что сокеты уже поддерживают таймауты чтения! Нужно ли настраивать какое-либо свойство (-и) на TcpClient
NetworkStream
? Проблема возникает на сервере? Сервер не закрывает соединения, это зависит от клиента. Вышеупомянутое также работает внутри контекста потока пользовательского интерфейса (тестовая программа), возможно, оно имеет какое-то отношение к этому...
Кто-нибудь знает, как правильно использовать NetworkStream.Read
для чтения данных, пока не появится больше данных? Я предполагаю, что то, что я желаю, - это что-то вроде старых свойств таймаута Win32 winsock... ReadTimeout
и т.д. Он пытается прочитать, пока не будет достигнут тайм-аут, а затем вернется 0... Но иногда кажется, что возвращается 0 когда данные должны быть доступны (или по пути.. может прочитать возврат 0, если он доступен?), и затем он блокируется бесконечно на последнем чтении, когда данные недоступны...
Да, я в недоумении!