Когда NetworkStream TcpClient завершает одну операцию чтения?

Я работаю над проектом, который включает связь между клиентом и сервером через TCP и буфер протокола Google. На стороне клиента я в основном использую NetworkStream.Read() для блокировки чтения с сервера через буфер массива байтов.

Согласно документации MSDN,

Этот метод считывает данные в параметр буфера и возвращает количество успешно прочитанных байтов. Если данных для чтения нет, метод Read возвращает 0. Операция Read считывает столько данных, сколько доступно, вплоть до числа байтов, указанного параметром размера. Если удаленный узел разрывает соединение и все доступные данные получены, метод чтения завершается немедленно и возвращает нулевые байты.

То же самое и с асинхронным чтением (NetworkStream.BeginRead и EndRead). Мой вопрос в том, когда возвращается Read()/EndRead()? Похоже, он вернется после того, как все байты в буфере будут заполнены. Но в моем собственном тестировании это не так. Байты, прочитанные за одну операцию, сильно различаются. Я думаю, что это имеет смысл, потому что, если на стороне сервера есть пауза при отправке сообщений, клиент не должен ждать, пока буфер чтения заполнится. Есть ли у Read()/EndRead() какой-то механизм тайм-аута?

Я пытался выяснить, как Mono реализует Read() в NetworkStream и отслеживал до тех пор, пока не будет вызван внешний метод Receive_internal().


person pippo    schedule 15.02.2014    source источник
comment
Я отредактировал ваш заголовок. См. Должны ли вопросы включать «теги» в свои заголовки?, если нет единого мнения, не следует.   -  person John Saunders    schedule 15.02.2014
comment
И кроме того, этот вопрос не имеет ничего общего с C# - это вопрос .NET.   -  person John Saunders    schedule 15.02.2014
comment
@JohnSaunders Спасибо за редактирование.   -  person pippo    schedule 15.02.2014
comment
Если бы чтение ожидало полного буфера данных, вы могли бы легко зайти в тупик, если удаленная сторона ожидает вашего ответа, а вы ждете полного буфера, который никогда не придет.   -  person usr    schedule 16.02.2014
comment
@usr да, я понимаю эту часть. но все же, когда Read() возвращается, предполагая, что буфер еще не заполнен?   -  person pippo    schedule 16.02.2014
comment
В соответствии с этой логикой он должен возвращаться без блокировки, если данные доступны. Даже если доступен всего один байт. Что конкретно вам не понятно?   -  person usr    schedule 16.02.2014
comment
@usr предполагает, что сервер отправляет одно сообщение (100 байт) каждые 50 мс, сколько байтов считывается на стороне клиента при одном вызове NetworkStream.Read()?   -  person pippo    schedule 16.02.2014
comment
Каждый вызов будет возвращать от одного байта до количества байтов, доступных без блокировки. Ничего, ничего, больше ничего не гарантируется. На практике вы получите один или несколько сетевых пакетов одновременно. Стек не имеет смысла удерживать доступные байты.   -  person usr    schedule 16.02.2014


Ответы (2)


Он считывает все данные, доступные в сетевом потоке или при заполнении буфера. Что наступит раньше. Вы уже заметили это поведение.

Таким образом, вам нужно будет обработать все байты и посмотреть, завершено ли сообщение. Вы делаете это, создавая сообщение. См. вопрос .NET об асинхронных операциях сокетов и кадрировании сообщений о том, как вы можете это сделать.

Что касается вопроса о тайм-ауте, если предположить, что вы спрашиваете, есть ли у beginread тайм-аут, я бы сказал «нет», потому что он просто ждет поступления данных в поток и помещения их в буфер, после чего вы можете обрабатывать входящие байты .

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

Обзор поведения BeginRead:

  1. Вызвать НачатьЧтение(); -> Ожидание поступления байтов в поток......
  2. В поток поступил 1 байт или более
  3. Начните помещать байт(ы) из шага 2 в буфер, который был задан
  4. Вызвать EndRead(); -> Байты в буфере могут быть обработаны EndRead();
  5. Наиболее распространенной практикой является повторное повторение всех этих шагов.
person Kay Tsar    schedule 15.02.2014
comment
Он считывает все данные, доступные в сетевом потоке. поскольку сетевой поток является непрерывным потоком, как определить точку отсечки для одной операции чтения сокета (предположим, что буфер настолько велик, что никогда не заполняется)? допустим, сервер отправляет одно сообщение (100 байт) каждые 50 мс, сколько байтов читается на стороне клиента при одном вызове NetworkStream.Read()? - person pippo; 16.02.2014
comment
Как указано ниже, каждый вызов будет возвращать от одного байта до количества доступных байтов без блокировки. Ничего, ничего, больше ничего не гарантируется. Это означает, что он просто проверит, есть ли данные в потоке. Это точка отсечки. Количество байтов, доступных каждый раз, зависит от таких факторов, как ваша сеть (задержка, маршрутизатор и т. д.) и ваш клиент. - person Kay Tsar; 16.02.2014

Если бы чтение ожидало полного буфера данных, вы могли бы легко зайти в тупик, если удаленная сторона ожидает вашего ответа, а вы ждете полного буфера, который никогда не придет.

В соответствии с этой логикой он должен возвращаться без блокировки, если данные доступны. Даже если доступен всего один байт.

предположим, что сервер отправляет одно сообщение (100 байт) каждые 50 мс, сколько байтов считывается на стороне клиента при одном вызове NetworkStream.Read()?

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

person usr    schedule 15.02.2014