TcpClient получает данные если делать паузу, что за бред ?
От: Аноним  
Дата: 22.02.07 13:19
Оценка:
Собственно пример из Helpa для TcpClient.Read()
do
{
        numberOfBytesRead = network.Read( m_buffer, 0, m_buffer.Length );  
        m_memory_stream.Write( m_buffer, 0, numberOfBytesRead );

}
while( network.DataAvailable);


Так вот, если ставлю брейкпоинт и отлаживаю по шагам то данные получаю полностью.
Когда брейкпоинт убираю, данные получаются частично например первые 4132 байт из 9665.

Каким образом гарантированно получить отправленный с хоста XML пакет ?
Неужели придется ставить паузу в цикле ?
Re: TcpClient получает данные если делать паузу, что за бред
От: cvetkov  
Дата: 22.02.07 13:48
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Так вот, если ставлю брейкпоинт и отлаживаю по шагам то данные получаю полностью.

А>Когда брейкпоинт убираю, данные получаются частично например первые 4132 байт из 9665.

а что значит полностью?
DataAvailable говорит лиш о наличии данных в буфере. если они туда еще не пришли то их там и не будет. тут надо самому определяться сколько данных ты ждеш. или ждать закрытия соединения.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: TcpClient получает данные если делать паузу, что за б
От: Аноним  
Дата: 22.02.07 13:53
Оценка:
Здравствуйте, cvetkov, Вы писали:

C>Здравствуйте, <Аноним>, Вы писали:


А>>Так вот, если ставлю брейкпоинт и отлаживаю по шагам то данные получаю полностью.

А>>Когда брейкпоинт убираю, данные получаются частично например первые 4132 байт из 9665.

C>а что значит полностью?

C>DataAvailable говорит лиш о наличии данных в буфере. если они туда еще не пришли то их там и не будет. тут надо самому определяться сколько данных ты ждеш. или ждать закрытия соединения.


А если хост мне шлет XML пакет заранее неизвестного размера, соединение при этом не рвется по завершению, то как сделать надежную реализацию ?

Как-то работают почтовые службы, непонятно...
Re[3]: TcpClient получает данные если делать паузу, что за б
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 22.02.07 14:01
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Здравствуйте, cvetkov, Вы писали:


C>>Здравствуйте, <Аноним>, Вы писали:


А>>>Так вот, если ставлю брейкпоинт и отлаживаю по шагам то данные получаю полностью.

А>>>Когда брейкпоинт убираю, данные получаются частично например первые 4132 байт из 9665.

C>>а что значит полностью?

C>>DataAvailable говорит лиш о наличии данных в буфере. если они туда еще не пришли то их там и не будет. тут надо самому определяться сколько данных ты ждеш. или ждать закрытия соединения.


А>А если хост мне шлет XML пакет заранее неизвестного размера, соединение при этом не рвется по завершению, то как сделать надежную реализацию ?


А>Как-то работают почтовые службы, непонятно...



Парсите xml и тогда вам сразу станет понятно, в какой момент пришли все данные.

В целом можно применить как минимум 3 подхода:
  1. Сделать пакеты одинаковой длины (не ваш случай).
  2. Сделать заголок в пакете, который будет указывать на длину данных, которые необходимо прочитать (опять не то).
  3. Задатьмаркеры окончания пакета (то что надо — в ваше мслучае маркером будет закрывающая > вашего хмла).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: TcpClient получает данные если делать паузу, что за б
От: Аноним  
Дата: 23.02.07 18:41
Оценка:
>В целом можно применить как минимум 3 подхода:
P>

    P>
  1. Сделать пакеты одинаковой длины (не ваш случай).
    P>
  2. Сделать заголок в пакете, который будет указывать на длину данных, которые необходимо прочитать (опять не то).
    P>
  3. Задатьмаркеры окончания пакета (то что надо — в ваше мслучае маркером будет закрывающая > вашего хмла).
    P>

Спасибо. Остановился на варианте 3).
Теперь выглядит так :
do
{
        numberOfBytesRead = network.Read( m_buffer, 0, m_buffer.Length );  
        try
        {
           XmlDocument doc = new XmlDocument();
           doc.Load( m_memory_stream );
        }
        catch ( System.Xml.XmlException )
        {
           bad_xml = true;
        }
        m_memory_stream.Write( m_buffer, 0, numberOfBytesRead );

}
while ( (network.DataAvailable) || ( bad_xml ));


Вот только хотелось бы избавится от XmlDocument, например использовать что-то вроде XmlValidateReader, но без DTD-схемы.
Т.е. исключительно находить рутовый элемент и проверять закрыт он или нет. Есть ли в стандартных инструментах .net что-то подобное ?

И еще проблемка — если сервер пришлет вдруг невалидный xml то все повиснет...похоже нужно еще таймаут прикручивать ...
Re[5]: TcpClient получает данные если делать паузу, что за б
От: Igor Sukhov  
Дата: 24.02.07 15:56
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>И еще проблемка — если сервер пришлет вдруг невалидный xml то все повиснет...похоже нужно еще таймаут прикручивать ...

тебе нужно использовать неблокируюшее чтение — NetworkStream.BeginRead + EndRead. Если повезет, то может быть даже от while удастся избаивиться.
... << RSDN@Home 1.2.0 alpha rev. 0>>
* thriving in a production environment *
Re: TcpClient получает данные если делать паузу, что за бред
От: Tom Россия http://www.RSDN.ru
Дата: 27.02.07 07:33
Оценка: +2
Здравствуйте, <Аноним>, Вы писали:

А>Собственно пример из Helpa для TcpClient.Read()

А>
А>do
А>{
А>        numberOfBytesRead = network.Read( m_buffer, 0, m_buffer.Length );  
А>        m_memory_stream.Write( m_buffer, 0, numberOfBytesRead );

А>}
А>while( network.DataAvailable);
А>


А>Так вот, если ставлю брейкпоинт и отлаживаю по шагам то данные получаю полностью.

А>Когда брейкпоинт убираю, данные получаются частично например первые 4132 байт из 9665.

А>Каким образом гарантированно получить отправленный с хоста XML пакет ?

А>Неужели придется ставить паузу в цикле ?

Это особенность протокола TCP, TCP это потоковый протокол, при этом, если ты послал одной посылкой XXX килобайт, то никто не даст тебе гарантии, что при приёме ты получишь все XXX килобайт одним куском (за одно чтение из сокета), ты можешь считать их частями по YYY байт, при этом, даже возможно, что начальная часть данных придёт, а после соединение разорвётся. Для того, что бы правильно читать из сокета обычно вводят заголовок каждого пакета, где как минимум пишут сигнатуру, размер всего пакета, лучше так же записать контрольную сумму. Таким образом, при чтении ты можешь вначале читать заголовок и после всегда будешь знать сколько данных для данного пакета необходимо вычитать, вне зависимости от того, какими частями эти данные появляются в сокете. Ты так же всегда будешь знать где закончился один пакет и начинается другой.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[2]: TcpClient получает данные если делать паузу, что за б
От: Аноним  
Дата: 27.02.07 17:18
Оценка:
Tom>Это особенность протокола TCP, TCP это потоковый протокол, при этом, если ты послал одной посылкой XXX килобайт, то никто не даст тебе гарантии, что при приёме ты получишь все XXX килобайт одним куском (за одно чтение из сокета), ты можешь считать их частями по YYY байт, при этом, даже возможно, что начальная часть данных придёт, а после соединение разорвётся. Для того, что бы правильно читать из сокета обычно вводят заголовок каждого пакета, где как минимум пишут сигнатуру, размер всего пакета, лучше так же записать контрольную сумму. Таким образом, при чтении ты можешь вначале читать заголовок и после всегда будешь знать сколько данных для данного пакета необходимо вычитать, вне зависимости от того, какими частями эти данные появляются в сокете. Ты так же всегда будешь знать где закончился один пакет и начинается другой.

Т.е. я так понял что для надежной передачи данных в военных условиях
необходимо над TCP надстраивать свой протокол, в котором как минимум передавать длинну блока данных.

Еще вопрос, если у меня будут отправлены два XML пакета

cначала send:
<root>
<data>1</data>
</root>


затем send:

<root>
<data>2</data>
</root>



может ли в очередном read получится следующее :
</root>
<root>
<data>2</data>
?

или пакет 1 и пакет 2 будут всегда в разных readах ?
Re[2]: TcpClient получает данные если делать паузу, что за б
От: tyger Россия  
Дата: 28.02.07 04:38
Оценка:
Здравствуйте, Tom, Вы писали:


Tom>Это особенность протокола TCP, TCP это потоковый протокол, при этом, если ты послал одной посылкой XXX килобайт, то никто не даст тебе гарантии, что при приёме ты получишь все XXX килобайт одним куском (за одно чтение из сокета), ты можешь считать их частями по YYY байт, при этом, даже возможно, что начальная часть данных придёт, а после соединение разорвётся. Для того, что бы правильно читать из сокета обычно вводят заголовок каждого пакета, где как минимум пишут сигнатуру, размер всего пакета, лучше так же записать контрольную сумму. Таким образом, при чтении ты можешь вначале читать заголовок и после всегда будешь знать сколько данных для данного пакета необходимо вычитать, вне зависимости от того, какими частями эти данные появляются в сокете. Ты так же всегда будешь знать где закончился один пакет и начинается другой.


Хм. А разве протокол TCP не является протоколом с подтверждением приема/передачи, в отличие от тогоже UDP? Если он правильно реализован, конечно. Или Вы сейчас говорите о изобретении своего какого-то протогола над IP? Просто пакеты на уровне TCP (и так оно было в винде в socks2.dll реализовано) дойти кривыми или дойти неизвестного размера не могли — там это контролировалось!!!
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: TcpClient получает данные если делать паузу, что за б
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 28.02.07 05:01
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>или пакет 1 и пакет 2 будут всегда в разных readах ?


они могут быть порезаны и склеены в любом месте
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re[3]: TcpClient получает данные если делать паузу, что за б
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 28.02.07 05:17
Оценка:
Здравствуйте, tyger, Вы писали:

T>Хм. А разве протокол TCP не является протоколом с подтверждением приема/передачи, в отличие от тогоже UDP? Если он правильно реализован, конечно.


является

T>Просто пакеты на уровне TCP (и так оно было в винде в socks2.dll реализовано) дойти кривыми или дойти неизвестного размера не могли — там это контролировалось!!!


речь о том, что в отличии от UDP/IP в TCP/IP для приемной стороны никаких пакетов нет, данные будут читаться из входного потока кусками, на которые произвольным образом могут быть порезаны отправленные данные, поэтому для отправляемых тобой единиц данных (строк, структур и т.д.) надо либо указывать в заголовке длину, либо обозначать конец каждой единицы, так чтобы на приемной строне их можно было правильно разделить и склеить.
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re[3]: TcpClient получает данные если делать паузу, что за б
От: Andrbig  
Дата: 28.02.07 08:39
Оценка:
Здравствуйте, tyger, Вы писали:

T>Хм. А разве протокол TCP не является протоколом с подтверждением приема/передачи, в отличие от тогоже UDP? Если он правильно реализован, конечно. Или Вы сейчас говорите о изобретении своего какого-то протогола над IP? Просто пакеты на уровне TCP (и так оно было в винде в socks2.dll реализовано) дойти кривыми или дойти неизвестного размера не могли — там это контролировалось!!!


TCP/IP:
1. гарантирует что все данные дойдут
2. не гарантирует, что дойдут одним куском
3. гарантирует, что если порежется, то куски дойдут в нужной последовательности
Re[4]: TcpClient получает данные если делать паузу, что за б
От: Pavel M. Россия  
Дата: 28.02.07 09:54
Оценка:
Здравствуйте, Andrbig, Вы писали:

A>Здравствуйте, tyger, Вы писали:


T>>Хм. А разве протокол TCP не является протоколом с подтверждением приема/передачи, в отличие от тогоже UDP? Если он правильно реализован, конечно. Или Вы сейчас говорите о изобретении своего какого-то протогола над IP? Просто пакеты на уровне TCP (и так оно было в винде в socks2.dll реализовано) дойти кривыми или дойти неизвестного размера не могли — там это контролировалось!!!


A>TCP/IP:

A>1. гарантирует что все данные дойдут
A>2. не гарантирует, что дойдут одним куском
A>3. гарантирует, что если порежется, то куски дойдут в нужной последовательности

если данные были фрагментированы в процессе передачи, то это никак не будет заметно пользователю и поток будет доступен только при получении всей последовательности....

Пример:
посылка "абвгдежзкилмн" -> фрагментация "абвгде" / "жзкилмн" -> дефрагментация "абвгде" + "жзкилмн" -> сообщение о получении данных, содержимое потока "абвгдежзкилмн"

насколько я мог понять из курса по сетям и опыта работы... иначе для пользователя был бы большой гемор... =)
--------------------------
less think — do more
Re[5]: TcpClient получает данные если делать паузу, что за б
От: Аноним  
Дата: 28.02.07 11:23
Оценка:
Здравствуйте, Pavel M., Вы писали:

PM>Здравствуйте, Andrbig, Вы писали:


A>>Здравствуйте, tyger, Вы писали:


T>>>Хм. А разве протокол TCP не является протоколом с подтверждением приема/передачи, в отличие от тогоже UDP? Если он правильно реализован, конечно. Или Вы сейчас говорите о изобретении своего какого-то протогола над IP? Просто пакеты на уровне TCP (и так оно было в винде в socks2.dll реализовано) дойти кривыми или дойти неизвестного размера не могли — там это контролировалось!!!


A>>TCP/IP:

A>>1. гарантирует что все данные дойдут
A>>2. не гарантирует, что дойдут одним куском
A>>3. гарантирует, что если порежется, то куски дойдут в нужной последовательности

PM>если данные были фрагментированы в процессе передачи, то это никак не будет заметно пользователю и поток будет доступен только при получении всей последовательности....


PM>Пример:

PM>посылка "абвгдежзкилмн" -> фрагментация "абвгде" / "жзкилмн" -> дефрагментация "абвгде" + "жзкилмн" -> сообщение о получении данных, содержимое потока "абвгдежзкилмн"

PM>насколько я мог понять из курса по сетям и опыта работы... иначе для пользователя был бы большой гемор... =)


Хе а если твое "абвгдежзкилмн" допустим 1 Гб по размеру? а RAM у тебя в машинке 256 Мб
Re[6]: TcpClient получает данные если делать паузу, что за б
От: Pavel M. Россия  
Дата: 28.02.07 11:44
Оценка:
Здравствуйте, Аноним, Вы писали:

PM>>насколько я мог понять из курса по сетям и опыта работы... иначе для пользователя был бы большой гемор... =)


А>Хе а если твое "абвгдежзкилмн" допустим 1 Гб по размеру? а RAM у тебя в машинке 256 Мб


Виртуальная память. И давайте не будем заниматься экстремизмом
--------------------------
less think — do more
Re: TcpClient получает данные если делать паузу, что за бред
От: Morpheus_  
Дата: 28.02.07 11:51
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Так вот, если ставлю брейкпоинт и отлаживаю по шагам то данные получаю полностью.

А>Когда брейкпоинт убираю, данные получаются частично например первые 4132 байт из 9665.

Когда ты ставишь брейкпоинт и идешь по шагам,то после вычитки буфера до следующей операции чтения происходит заполнение буфера сокета на уровне системы, когда программа работает, то буфер заполнятся не успевает

А>Каким образом гарантированно получить отправленный с хоста XML пакет ?

А>Неужели придется ставить паузу в цикле ?

нет, не нужно, просто происходит вот что — ты передаешь 10 КБ, на приемной стороне вызываешь чтение сокета, но прочитать сразу 10 КБ ты не можешь — можно прочитать только столько, сколько есть в приемном буфере сокета. Размер этого буфера зависит от системы и настраивается гдето в реестре.

Так вот вычитав буфер (допустим 4 КБ) ты проверяешь свойство DataAvailable, однако оно сразу после вычитки всего буфера будет всегда false, т.к. в буфер еще не успела прийти очередная порция данных, а ты на этом соединение разрываешь, а не стоило этого делать...
нужно было вызывать Receive до тех пор пока не будет принят весь блок 10 КБ!

Свойство DataAvailable говорит только о том что в приемный буфер поступили данные, поэтому по нему никак не определишь все ли данные поступили. Т.е. если в буфер успел записаться 1 байт из 10 КБ то свойство это станет true, но если этот байт вычитать и тутже проверить DataAvailable то оно всегда будет false, т.к. следующий байт в буфер еще не успел прийти и буфер пустой, а соответственно и данных пока еще нету, т.е. DataAvailable=false.
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[2]: TcpClient получает данные если делать паузу, что за б
От: Morpheus_  
Дата: 28.02.07 11:57
Оценка:
Забыл предупредить, если ты читаешь из сокета 100000 байт, это не значит что операция чтения завершится когда будут прочитаны все 100000 байт.
Операция чтения завершится когда будет вычитан весь системный буфер (на разных системах по разному, как правило порядка 4 КБ...8 КБ), поэтому операцию чтения нужно повторять до тех пор пока не будут вычитаны все 100000 байт небольшими блоками.
Операция Receive возвращает кол-во принятых байт, так что вычесть из 100000 это значение и запустить опять Receive для оставшихся байт не составит труда
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[5]: TcpClient получает данные если делать паузу, что за б
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 28.02.07 12:30
Оценка:
Здравствуйте, Pavel M., Вы писали:

PM>насколько я мог понять из курса по сетям и опыта работы... иначе для пользователя был бы большой гемор... =)


странный был курс, посмотри хотя бы Эффективное программирование TCP/IP
Автор: Zinya
Дата: 17.11.04
"Совет 6. Помните, что TCP — потоковый протокол"

TСР — потоковый протокол. Это означает, что данные доставляются получателю в виде потока байтов, в котором нет понятий «сообщения» или «границы сообщения». В этом отношении чтение данных по протоколу TCP похоже на чтение из последовательного порта — заранее не известно, сколько байтов будет возвращено после обращения к функции чтения.


и дальше с картинками и на пальцах
... << RSDN@Home 1.2.0 alpha rev. 675>>
Re[4]: TcpClient получает данные если делать паузу, что за б
От: Tom Россия http://www.RSDN.ru
Дата: 28.02.07 13:34
Оценка: 1 (1)
A>TCP/IP:
A>1. гарантирует что все данные дойдут

Это стандартное заблуждение, не гарантирует он доставку, и что дойдут все данные, для это специальный софт придумали, аля MSMQ, IBM MQ Series итп... Послав однажды 100kb ты можешь принять из них первые скажем 20 и потом соединение порвётся. Даже определение того, что соединение
порвалось — обычно задача уровня приложения, хотя SIO_KEEPALIVE_VALS в принципе помогает.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[6]: TcpClient получает данные если делать паузу, что за б
От: Pavel M. Россия  
Дата: 28.02.07 13:54
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>Здравствуйте, Pavel M., Вы писали:


PM>>насколько я мог понять из курса по сетям и опыта работы... иначе для пользователя был бы большой гемор... =)


OE>странный был курс, посмотри хотя бы Эффективное программирование TCP/IP
Автор: Zinya
Дата: 17.11.04
"Совет 6. Помните, что TCP — потоковый протокол"


OE>

OE>TСР — потоковый протокол. Это означает, что данные доставляются получателю в виде потока байтов, в котором нет понятий «сообщения» или «границы сообщения». В этом отношении чтение данных по протоколу TCP похоже на чтение из последовательного порта — заранее не известно, сколько байтов будет возвращено после обращения к функции чтения.


OE>и дальше с картинками и на пальцах


я имел в виду фрагментацию на сетевом уровне... Если вы работали с сетью, то знаете, что никогда сообщение вида "This is my message", при чтении в буфер, допустим из 10 байт (пускай, текст в юникоде), не прийдет так "Th" "is " "my"... а всегда будет полное наполнение буфера, вида "This "+"is my"+" mess" + "age"... в конце будет неполный буффер. И еще, возможно я ошибаюсь, но библа не скажет о доступности текста, пока не прийдет весь текст, то есть полная цепочка пакетов.
Это к этому.

A>2. не гарантирует, что дойдут одним куском
A>3. гарантирует, что если порежется, то куски дойдут в нужной последовательности

Если у вас есть контрпример в коде, жду. Например, когда отправили "1234567890", а на вход получили "12345_____" и "67890_____", где _ — незаполненные байты буффера получения.
--------------------------
less think — do more
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.