Как правильно использовать TcpClient ReadTimeout

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

Проблема в том, что если вы используете свойство TcpClient ReadTimeout и ваша операция чтения фактически истекает, Microsoft решила закрыть сокет. Это не ожидается, нежелательно, не выполняется ни одной другой известной мне реализацией сокета, и не имеет веских причин, по которым это должно иметь место, кроме лени программиста. Но это то, что Microsoft решила сделать.

В любом случае, все обходные пути, которые я нашел, в том числе на этом сайте, имели различные способы выполнения той или иной формы опроса занятости, а некоторые даже включали запуск еще одного потока для выполнения простого вызова чтения. Извините, но у меня есть дела поважнее с моим процессором, чем сидеть и опрашивать, особенно когда открыто много сокетов, так что это не мой вариант. В конце концов, это не начало 1990-х годов, когда опросы были просто способом, которым вы занимались. В настоящее время у нас есть такая вещь, как операционные системы, которые довольно эффективно заботятся о таких вещах, используя прерывания.

В любом случае, при еще одном косвенном поиске я наткнулся на этот старый пост в блоге:

http://blogs.msdn.com/b/mflasko/archive/2006/02/20/535655.aspx

Блоги MSDN > Блог Майка Фласко > Обработка тайм-аута при чтении сетевых данных

Ключевые выводы, которые подскажут вам, как правильно обрабатывать тайм-ауты чтения:

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

и решение:

Лучший подход — перехватить исключение, закрыть сокет или TCPClient и при необходимости переподключиться.

Хотя я все еще думаю, что это создает ненужную нагрузку на пользователя API, по крайней мере, это наиболее правильное решение, которое я смог найти из десятков сайтов, которые я просматривал, пытаясь понять, как сделать полуправильный ReadTimeout сокета.

Я надеюсь, что этот вопрос / комментарий сэкономит кому-то часы, которые мне потребовались, чтобы найти.


person Dunk    schedule 01.06.2012    source источник
comment
Я тоже работал с этим в последнее время. Если я устанавливаю тайм-аут на 1000 мс и ловлю исключение, иногда я могу в конечном итоге задержать некоторые процедуры, потому что довольно сложно определить, действительно ли передача закончилась ИЛИ у вас возникла проблема с сетью. Например, у меня есть часть кода, которая передает изображение PNG по сети, код примерно такой, как while (true) { try Получить данные и поместить в 4096-байтовый буфер прерывается при исключении; затем, если данные недоступны, прервите время; } Если я не переведу поток в спящий режим на 1 мс (я знаю, что это отстой), имеющиеся данные слишком быстро вернут значение false, и изображение будет удалено.   -  person Felype    schedule 11.02.2014
comment
Это вопрос? Я чувствую, что было бы намного лучше, если бы это было в формате вопросов и ответов, даже если вы отвечаете на свой вопрос.   -  person Tim Lovell-Smith    schedule 01.04.2014
comment
Название - вопрос. Я, конечно, мог бы задать вопрос и ответить в отдельном ответе, но вместо этого сделал это так. Это был первоначальный вопрос, который я собирался задать, но прежде чем нажать кнопку «Опубликовать», я подумал, что должен провести достаточно исследований, чтобы задать более обоснованный вопрос. Однако я не представлял себе, сколько времени займет это маленькое начинание. В процессе я ответил на свой вопрос. Поскольку поиск приемлемого решения занял так много времени, я подумал, что было бы неплохо избавить других от необходимости повторять все часы исследований, которые я должен был провести.   -  person Dunk    schedule 03.04.2014
comment
...Другой альтернативой было бы просто вообще не задавать вопрос. Но я думал, что это будет полезно для других.   -  person Dunk    schedule 03.04.2014
comment
@Dunk Спасибо за этот пост с вопросами и ответами, я сейчас борюсь с этой проблемой. Я написал свое клиентское приложение TCP Server, используя свойство ReadTimeout, поймал исключение и повторил чтение в том же NetStream. Что интересно, на Win 7 работает, а на Win XP нет. После получения IOException от ReadTimeout в Win XP сокет будет закрыт.   -  person Lazureus    schedule 04.11.2014


Ответы (1)


то, что вы ищете, - это методы Poll или Select, они позволяют вам ждать данных с тайм-аутом, не закрывая базовые соединения:

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.poll%28v=vs.110%29.aspx http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.select%28v=vs.110%29.aspx

person Dieter DHoker    schedule 14.02.2014