Итак, в этом видео мы поговорим
про обработку сетевых ошибок, а также обсудим таймауты для сокетов.
Как правило, все обучающие примеры
для работы с сетью выглядят очень просто.
На самом деле, как дело доходит до настоящих программ,
которые работают в нашей жизни,
они все выглядят гораздо сложнее.
Связано это прежде всего с обработкой ошибок.
Как правило, сеть может работать стабильно не всегда.
В ней могут появляться задержки, могут не доходить пакеты,
а также могут быть разрывы соединений.
Поэтому при написании ваших сетевых программ
необходимо быть к этому готовыми.
Необходимо работать с сокетами правильно.
Прежде всего нужно задавать таймауты при сетевых операциях,
а также очень грамотно обрабатывать сетевые ошибки.
Давайте рассмотрим обучающий пример,
в котором создается тот же самый знакомый нам код сервера.
Мы создаем сокет при помощи контекстного менеджера.
Вызываем методы bind и listen.
Затем в бесконечном цикле вызываем метод accept.
И слушаем наш сокет, получаем новое соединение.
После того, как мы получили это соединение, мы вызываем
метод settimeout для нашего объекта.
И передаем туда значение "5".
По умолчанию все вызовы для этого объекта соединения,
например вызов recv, или вызов send,
они будут заблокированы до тех пор, пока данные
на другой стороне кто-то не сможет прочитать или записать.
По умолчанию таймаута нет.
Мы можем передать значение None и это
как раз будет значением по умолчанию.
Если мы передадим timeout = 0, это будет означать немного другое.
Это переведет наш сокет в неблокирующий режим.
Про неблокирующий режим мы будем говорить чуть позднее.
Также можно задать свой таймаут.
Итак, если мы задали таймаут и вызвали метод recv у нашего сокета,
и в этот сокет не поступило данных в течении пяти секунд,
то будет сгенерировано исключение socket.timeout.
Его можно перехватить и обработать.
Как обрабатывать, вам нужно решать самим.
Можно, например, закрывать соединение.
Можно, например, если мы пишем в это соединение, повторно отправлять
туда данные, или делать retry.
Все зависит от требований к вашей программе.
Но если вы работаете с таймаутами, вам нужно быть готовым к этому
как на стороне сервера, так и на стороне клиента.
Итак, в данном случае мы просто закрываем соединение.
Метод close будет вызван автоматически, когда будет выход
из нашего контекстного менеджера.
Рассмотрим код на клиенте.
На клиенте существует так называемый connect timeout и socket read timeout.
Их еще называют именно так.
connect timeout мы задаем в методе create_connection
и этот таймаут будет распространяться только на установку
соединения с нашим сервером.
То есть если в течении 5 секунд
наш сервер не смог подключить соединение,
и наше соединение не было установлено,
то возникнет исключение socket.timeout и нам на стороне
клиента нужно будет его обработать.
То есть сделать переподключение,
подождать некоторое время
и попробовать создать это соединение снова.
В данном случае эти таймауты могут немножко различаться.
Так как, например, на установку соединения может требоваться
немного больше времени, поэтому этот таймаут может быть задан большим.
После того, как соединение установлено, мы можем задать
таймаут на все операции с нашим сокетом.
Например, если мы не смогли записать данные,
или прочитать данные с сокета,
то сделать соответствующую обработку.
Также может возникнуть любое другое исключение
и его точно так же нужно будет обработать.
Базовый класс для обработки
исключений модуля socket - это socket.error.
Давайте попробуем запустить наш пример
и посмотрим, как работают таймауты в консоли.
Для этого нам потребуется код нашего сервера.