2008-10-03 2 views
4

Для моего текущего проекта мне нужно запросить данные XML через соединение сокета tcp/ip. Для этого я использую класс TcpClient:Соединения сокета Tcp/Ip в .NET

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-документа, но я обнаружил, что между потоком. Чтение вызывает, что базовый поток иногда закрывается, и я пропускаю последнюю часть данных.

ответ

3

Вы создаете петлю для чтения.

Stream.Read возвращает int для байтов, которые он читал до сих пор, или 0, если конец потока достигнут.

Так, его, как:

int bytes_read = 0; 
while (bytes_read < buffer.Length) 
    bytes_read += stream.Read(buffer, bytes_read, buffer.length - bytes_read); 

EDIT: Теперь, вопрос в том, как вы определяете размер буфера. Если ваш сервер сначала отправит размер, это нормально, вы можете использовать приведенный выше фрагмент. Но если вам нужно прочитать, пока сервер не закроет соединение, вам нужно использовать 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(); 
} 
+0

Это то, что я сделал, но основной поток закрывался между чтениями. Как это объяснить? – 2008-10-03 19:14:22

2

Чтение не гарантирует полного считывания потока. Он возвращает количество действительных байтов чтения и 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()); 
} 
0

Я настоятельно рекомендую вам попробовать WCF для выполнения таких задач. Это дает вам, после не столь крутой кривой обучения, много преимуществ по сравнению с сырой связью сокетов. Для этой задачи я согласен с предыдущими ответами, вы должны использовать цикл и динамически выделять память по мере необходимости.

Смежные вопросы