Хотя наш клиент в конце концов обнаруживает, что собеседник выключен или недоступен, бывает, что нужно определить это раньше, чем пройдут условленные девять минут. В таком случае следует поместить тайм-аут в вызов функции readline
, о чем рассказывается в разделе 14.2.
В описанном сценарии сбой на узле сервера можно обнаружить, только послав данные на этот узел. Если мы хотим обнаружить сбой на узле сервера, не посылая данные , требуется другая технология. Мы рассмотрим параметр сокета SO_KEEPALIVE
в разделе 7.5.
5.15. Сбой и перезагрузка на узле сервера
В этом сценарии мы устанавливаем соединение между клиентом и сервером и затем считаем, что на узле сервера происходит сбой, после чего узел перезагружается. В предыдущем разделе узел сервера был выключен, когда мы отправляли ему данные. Здесь же перед отправкой данных серверу узел сервера перезагрузится. Простейший способ имитировать такую ситуацию — установить соединение, отсоединить сервер от сети, выключить узел сервера и перезагрузить его, а затем снова присоединить узел сервера к сети. Мы не хотим, чтобы клиент знал о завершении работы сервера (о такой ситуации речь пойдет в разделе 5.16).
Как было сказано в предыдущем разделе, если клиент не посылает данные серверу, то он не узнает о произошедшем на узле сервера сбое. (При этом считается, что мы не используем параметр сокета SO_KEEPALIVE
.) События развиваются следующим образом:
1. Мы запускаем сервер, затем — клиент, и вводим строку для проверки установленного соединения. Получаем ответ сервера.
2. Узел сервера выходит из строя и перезагружается.
3. Мы вводим строку на стороне клиента, которая посылается как сегмент данных TCP на узел сервера.
4. Когда узел сервера перезагружается после сбоя, его TCP теряет информацию о существовавших до сбоя соединениях. Следовательно, TCP сервера отвечает на полученный от клиента сегмент данных, посылая RST.
5. Наш клиент блокирован в вызове функции readline
, когда приходит сегмент RST, заставляющий функцию readline
возвратить ошибку ECONNRESET
.
Если для нашего клиента важно диагностировать выход из строя узла сервера, даже если клиент активно не посылает данные, то требуется другая технология (с использованием параметра сокета SO_KEEPALIVE
или некоторых функций, проверяющих наличие связи в клиент-серверном соединении).
5.16. Выключение узла сервера
В двух предыдущих разделах рассматривался выход из строя узла сервера или недоступность узла сервера в сети. Теперь мы рассмотрим, что происходит, если узел сервера выключается оператором в то время, когда на этом узле выполняется наш серверный процесс.
Когда система Unix выключается, процесс init
обычно посылает всем процессам сигнал SIGTERM
(мы можем перехватить этот сигнал), ждет в течение некоторого фиксированного времени (часто от 5 до 20 с), а затем посылает сигнал SIGKILL
(который мы перехватить не можем) всем еще выполняемым процессам. Это дает всем выполняемым процессам короткое время для завершения работы. Если мы не завершили выполнение процесса, это сделает сигнал SIGKILL
. При завершении процесса закрываются все открытые дескрипторы, а затем мы проходим ту же последовательность шагов, что описывалась в разделе 5.12. Там же было отмечено, что в нашем клиенте следует использовать функцию select
или poll
, чтобы клиент определил завершение процесса сервера, как только оно произойдет.
5.17. Итоговый пример TCP
Прежде чем клиент и сервер TCP смогут взаимодействовать друг с другом, каждый из них должен определить пару сокетов для соединения: локальный IP-адрес, локальный порт, удаленный IP-адрес, удаленный порт. На рис. 5.5 мы схематически изображаем эти значения черными кружками. На этом рисунке ситуация представлена с точки зрения клиента. Удаленный IP-адрес и удаленный порт должны быть заданы клиентом при вызове функции connect
. Два локальных значения обычно выбираются ядром тоже при вызове функции connect
. У клиента есть выбор: он может задать только одно из локальных значений или оба, вызвав функцию bind
перед вызовом функции connect
, однако второй подход используется редко.
Рис. 5.5. TCP-соединение клиент-сервер с точки зрения клиента
Как мы отмечали в разделе 4.10, клиент может получить два локальных значения, выбранных ядром, вызвав функцию getsockname
после установления соединения.
Читать дальше
Конец ознакомительного отрывка
Купить книгу