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

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

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

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

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

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

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

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

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

и решение:

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

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

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

27
задан Dunk 1 June 2012 в 15:30
поделиться