Понимание тайм-аутов сокетов Indy

#sockets #delphi #indy

Вопрос:

Я хочу понять, как работают тайм-ауты сокетов Indy, потому что я хочу использовать их следующим образом.

У меня есть приложение (TCP-сервер/клиент), которое передает файл через Интернет. Когда я начинаю передачу, я хочу иметь возможность остановить ее достаточно быстро (скажем, 1500 мс), если я решу это. Если какая-то розетка считывает данные, и что-то происходит на проводе, из-за чего он опаздывает, я не смогу остановить передачу, потому что розетка зависла, считывая данные. Поэтому мне нужно установить несколько коротких тайм-аутов, которые при нормальной работе не будут срабатывать. Но если что-то случится и данные будут запаздывать, управление будет передано главному процессу, и я смогу проверить запрос на прерывание.

Теперь я не знаю, что делать дальше… Если время ожидания считывания сокета истекло, что это значит? Сокет не получал никаких данных за этот период времени… Или сокет получил некоторые данные в буфере, но не успевает закончить? У меня такое чувство, что эти тайм-ауты-это периоды ожидания того, что что-то произойдет (начнется операция чтения или записи). Но (допустим, чтение), после запуска, что произойдет, если сокет получит половину данных (которые его попросили прочитать), а затем ничего не придет? Будет ли этот вызов навсегда блокировать выполнение программы? Потому что, если это произойдет, я снова не смогу проверить запрос на прерывание.

В любом случае… когда наступит тайм-аут, это вызовет исключение? Я могу поймать его и попробовать снова, в той же связи, как будто ничего не случилось? Будет ли буфер входа/выхода изменен после тайм-аута?

Я использую это, чтобы установить тайм-ауты чтения и записи:

 Socket.ReadTimeout:= WorkingRTimeOut; Socket.Binding.SetSockOpt(SOL_SOCKET, SO_SNDTIMEO, WorkingWTimeOut);  

Ответ №1:

Тайм-ауты сокетов применяются на основе каждого байта.

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

Если вы попросите сокет отправить N байтов, он примет столько байтов, сколько сможет, максимум до N байтов, в буфер записи сокета. Он может (и иногда делает) буферизировать меньшее количество байтов, требуя другой отправки для буферизации оставшихся байтов. Если наступает тайм — аут, это означает, что буфер записи сокета заполнен, получатель читает недостаточно быстро (или вообще), чтобы вовремя освободить место в буфере записи отправителя.

Если вы попросите Indy прочитать/отправить N байтов, он может выполнить несколько внутренних операций чтения/отправки сокетов, ожидая получения/отправки всех ожидаемых байтов. Таким образом, он мог прочитать/отправить X количество байтов, где X Конечно, вы можете попробовать еще раз прочитать/отправить, запросив только оставшиеся байты, которые вы еще не получили/отправили (N — X), но не запрашивайте байты, которые вы уже получили/отправили (X). Вы можете получить/отправить больше байтов или получить еще один тайм-аут, об этом невозможно узнать, пока вы не попробуете. Однако, в зависимости от контекста, может быть нелегко/невозможно узнать, сколько байтов было получено/отправлено до истечения тайм-аута, поэтому вы можете не знать, сколько оставшихся байтов нужно запросить снова. В этом случае все, что вы можете разумно сделать, это просто закрыть TCP-соединение, повторно подключиться и возобновить/начать все сначала.

Что касается вашей способности быстро прервать соединение, вы можете переместить код чтения/отправки в рабочий поток, а затем Disconnect() в сокет из основного процесса, когда это необходимо. Это, как правило, приведет к прекращению любого процесса блокировки чтения/отправки.

Комментарии:

1. Но когда наступает тайм-аут, я могу быть уверен, что ни один байт не был отправлен или получен даже в операции Indy ?

2. @MarusNebunu нет, некоторые байты могли быть отправлены/получены. Я сказал об этом в своем ответе. Прочитайте 3-й абзац более внимательно