Для моего текущего проекта мне нужно запросить данные XML через соединение сокета tcp / ip. Для этого я использую класс TcpClient:
Dim client As New TcpClient()
client.Connect(server, port)
Dim stream As NetworkStream = client.GetStream()
stream.Write(request)
stream.Read(buffer, 0, buffer.length)
// Output buffer and return results...
Теперь это отлично работает и для небольших ответов. Однако, когда я начинаю получать большие блоки данных, кажется, что данные передаются через соединение сокета пакетами. Когда это происходит, вызов stream.Read считывает только первый пакет, и поэтому я пропускаю остальную часть ответа.
Как лучше всего решить эту проблему? Первоначально я пытался просто выполнить цикл до тех пор, пока у меня не будет действительного XML-документа, но я обнаружил, что между вызовами stream.Read базовый поток иногда отключался, и я пропускал последнюю часть данных.





Вы создаете цикл для чтения.
Stream.Read возвращает int для байтов, которые он прочитал до сих пор, или 0, если достигнут конец потока.
Итак, это похоже на:
int bytes_read = 0;
while (bytes_read < buffer.Length)
bytes_read += stream.Read(buffer, bytes_read, buffer.length - bytes_read);
Обновлено: теперь вопрос в том, как вы определяете размер буфера. Если ваш сервер сначала отправляет размер, ничего страшного, вы можете использовать приведенный выше фрагмент. Но если вам нужно читать, пока сервер не закроет соединение, вам нужно использовать try / catch (что является хорошей идеей, даже если вы знаете размер) и использовать bytes_read, чтобы определить, что вы получили.
int bytes_read = 0;
try
{
int i = 0;
while ( 0 < (i = stream.Read(buffer, bytes_read, buffer.Length - bytes_read) )
bytes_read += i;
}
catch (Exception e)
{
//recover
}
finally
{
if (stream != null)
stream.Close();
}
Поместите его в блок try / catch. Если поток закрыт, скорее всего, ваш сервер не работает должным образом.
Кроме того, я не знаю, сколько байтов я должен получать для каждого ответа.
Сервер в порядке. Я отследил ответ с помощью программы, и она действительно отправляет полный ответ. Проблема в том, что соединение поддерживает только определенное количество байтов за передачу. После завершения передачи он закрывает базовый поток.
Чтение может возвращать 0 в EOF - я думаю, было бы лучше проверить это в цикле, потому что либо он будет возвращать 0, либо выбросить.
Чтение не гарантирует полного чтения потока. Он возвращает количество фактически прочитанных байтов и 0, если байтов для чтения больше нет. Вы должны продолжать цикл, чтобы прочитать все данные из потока.
Это возможный способ сделать это и получить в «ответе» строку ответа. Если вам нужен массив байтов, просто сохраните ms.ToArray ().
string response;
TcpClient client = new TcpClient();
client.Connect(server, port);
using (NetworkStream ns = c.GetStream())
using (MemoryStream ms = new MemoryStream())
{
ns.Write(request);
byte[] buffer = new byte[512];
int bytes = 0;
while(ns.DataAvailable)
{
bytes = ns.Read(buffer,0, buffer.Length);
ms.Write(buffer, 0, bytes);
}
response = Encoding.ASCII.GetString(ms.ToArray());
}
Я настоятельно рекомендую вам попробовать WCF для таких задач. Это дает вам после не столь крутой кривой обучения много преимуществ по сравнению с обычным обменом данными через сокеты. Для поставленной задачи, я согласен с предыдущими ответами, вы должны использовать цикл и динамически выделять память по мере необходимости.
Я так и сделал, но основной поток закрывался между чтениями. Как это объяснить?