Запуск ветвящегося сервера

zapusk vetvyashhegosya servera Сетевые сценарии

Некоторые части этого сценария написаны довольно замысловато, и большинство библиотечных вызовов в нем работает только в Unix-подобных системах. Важно, что в Windows он может выполняться под управлением Python для Cygwin, но не под управлением стандартной версии Python для Windows. Однако, прежде чем подробно вникать во все детали ветвления, рассмотрим, как наш сервер обрабатывает несколько клиентских запросов.

Прежде всего, обратите внимание, что для имитации продолжительных операций (таких, как обновление базы данных или пересылки информации по сети) этот сервер добавляет пятисекундную задержку с помощью time.sleep внутри функции handleClient обработки запроса клиента. После задержки клиенту возвращается ответ, как и раньше. Это значит, что на этот раз клиенты будут получать ответ не ранее, чем через 5 секунд после отправки запроса серверу.

Чтобы помочь следить за запросами и ответами, сервер выводит свое системное время при каждом получении запроса от клиента и добавляет свое системное время к ответу. Клиенты выводят время ответа, полученное с сервера, а не свое собственное — часы на сервере и у клиента могут быть установлены совершенно по-разному, поэтому, чтобы складывать яблоки с яблоками, все действия отмечаются временем сервера. Из-за имитируемой задержки в Windows обычно приходится запускать каждый сценарий клиента в собственном окне консоли (на некоторых платформах клиенты остаются в заблокированном состоянии, пока не получат свой ответ).

Но самое важное здесь, что сценарий выполняет на компьютере сервера один главный родительский процесс, единственной функцией которого является ожидание запросов на соединение (в функции dispatcher), плюс один дочерний процесс на каждое активное соединение с клиентом, выполняемый параллельно с главным родительским процессом и другими клиентскими процессами (в функции handleClient). В принципе, сервер может обрабатывать запросы от любого количества клиентов без заминок.

Для проверки запустим сервер удаленно в окне SSH или Telnet и запустим три клиента локально в трех разных окнах консоли. Как мы увидим чуть ниже, этот сервер можно также запускать локально, в оболочке Cygwin, если у вас есть она, но нет учетной записи на удаленном сервере, таком как learningpython.com, используемый здесь:

[ок но сервера (SSH или Telnet)]

[…]$ uname -p -o

i686 GNU/Linux

[…]$ python fork-server.py

Server connected by (‘72.236.109.185’, 58395) at Sat Apr 24 06:46:45 2010

Server connected by (‘72.236.109.185’, 58396) at Sat Apr 24 06:46:49 2010

Server connected by (‘72.236.109.185’, 58397) at Sat Apr 24 06:46:51 2010

[окно клиента 1]

C:\\PP4E\Internet\Sockets> python echo-client.py learning-python.com Client received: b"Echo=>b’Hello network world’ at Sat Apr 24 06:46:50 2010"

[окно клиента 2]

C:\\PP4E\Internet\Sockets> python echo-client.py learning-python.com Bruce

Client received: b"Echo=>b’Bruce’ at Sat Apr 24 06:46:54 2010"

[окно клиента 3]

C:\\Sockets> python echo-client.py learning-python.com The Meaning of Life

Client received: b"Echo=>b’The’ at Sat Apr 24 06:46:56 2010"

Client received: b"Echo=>b’Meaning’ at Sat Apr 24 06:46:56 2010"

Client received: b"Echo=>b’of’ at Sat Apr 24 06:46:56 2010"

Client received: b"Echo=>b’Life’ at Sat Apr 24 06:46:57 2010"

И снова все значения времени соответствуют времени на сервере. Это может показаться немного странным, поскольку участвуют четыре окна. На обычном языке этот тест можно описать так:

1.    На удаленном компьютере запускается сервер.

2.    Запускаются все три клиента, которые соединяются с сервером примерно в одно и то же время.

3.    На сервере три клиентских запроса запускают три дочерних процесса, которые сразу приостанавливаются на пять секунд (изображая занятость чем-то полезным).

4.    Каждый клиент ждет ответа сервера, который генерируется через пять секунд после получения запроса.

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

В действующем приложении такая задержка могла бы оказаться роковой, если бы к серверу попытались подключиться сразу нескольких клиентов — сервер застрял бы на операции, которую мы имитируем с помощью time.sleep, и не вернулся бы в главный цикл, чтобы принять новые запросы клиентов. При ветвлении, при котором на каждый запрос отводится по процессу, все клиенты могут обслуживаться параллельно.

Обратите внимание, что здесь используется прежний сценарий клиента (echoclient.py из примера 12.2), а сценарий сервера — другой. Клиенты просто посылают свои данные компьютеру сервера в указанный порт и получают их оттуда, не зная, каким образом обслуживаются их запросы на сервере. Отображаемый результат содержит строку байтов, вложенную в другую строку байтов. Это обусловлено тем, что клиент отправляет серверу какую-то строку байтов, а сервер возвращает какую-то строку обратно — сервер использует операции форматирования строк и кодирования вместо конкатенации строк байтов, поэтому клиентское сообщение отображается здесь явно, как строка байтов.

Другие способы запуска: локальные серверы в Cygwin и удаленные клиенты

Обратите также внимание, что сервер удаленно выполняется на компьютере с операционной системой Linux. Как мы узнали в главе 5, на момент написания книги функция fork не поддерживается в Python для Windows. Однако сервер может выполняться под управлением Python для Cygwin, что позволяет запустить его локально на компьютере localhost, где запускаются клиенты:

[окно оболочки Cygwin]

[C:\\PP4E\Internet\Socekts]$ python fork-server.py

Server connected by (‘127.0.0.1’, 58258) at Sat Apr 24 07:50:15 2010

Server connected by (‘127.0.0.1’, 58259) at Sat Apr 24 07:50:17 2010

[консоль Windows, тот же компьютер]

C:\\PP4E\Internet\Sockets> python echo-client.py localhost bright side of life

Client received: b"Echo=>b’bright’ at Sat Apr 24 07:50:20 2010"

Client received: b"Echo=>b’side’ at Sat Apr 24 07:50:20 2010"

Client received: b"Echo=>b’of’ at Sat Apr 24 07:50:20 2010"

Client received: b"Echo=>b’life’ at Sat Apr 24 07:50:20 2010"

[консоль Windows, тот же компьютер]

C:\\PP4E\Internet\Sockets> python echo-client.py

Client received: b"Echo=>b’Hello network world’ at Sat Apr 24 07:50:22 2010"

Можно запустить этот тест целиком на удаленном сервере Linux посредством двух окон SSH или Telnet. Он будет действовать примерно так же, как при запуске клиентов на локальном компьютере, в окне консоли DOS, но здесь «локальный» означает удаленный компьютер, с которым вы работаете локально. Забавы ради попробуем также соединиться с удаленным сервером из клиента, запущенного локально, чтобы показать, что сервер может быть доступным из Интернета в целом — когда серверы запрограммированы с сокетами и ветвятся подобным образом, клиенты могут подключаться к ним, находясь на любых компьютерах, и их запросы могут поступать одновременно:

[одно окно SSH (или Telnet)]

[…]$ python fork-server.py

Server connected by (‘127.0.0.1’, 55743) at Sat Apr 24 07:15:14 2010

Server connected by (‘127.0.0.1’, 55854) at Sat Apr 24 07:15:26 2010

Server connected by (‘127.0.0.1’, 55950) at Sat Apr 24 07:15:36 2010

Server connected by (‘72.236.109.185’, 58414) at Sat Apr 24 07:19:50 2010

[другое окно SSH, тот же компьютер]

[…]$ python echo-client.py

Client received: b"Echo=>b’Hello network world’ at Sat Apr 24 07:15:19 2010" […]$ python echo-client.py localhost niNiNI!

Client received: b"Echo=>b’niNiNI!’ at Sat Apr 24 07:15:31 2010"

[…]$ python echo-client.py localhost Say no more!

Client received: b"Echo=>b’Say’ at Sat Apr 24 07:15:41 2010"

Client received: b"Echo=>b’no’ at Sat Apr 24 07:15:41 2010"

Client received: b"Echo=>b’more!’ at Sat Apr 24 07:15:41 2010"

[консоль Windows, локальный компьютер]

C:\\Internet\Sockets> python echo-client.py learning-python.com Blue, no yellow!

Client received: b"Echo=>b’Blue,’ at Sat Apr 24 07:19:55 2010"

Client received: b"Echo=>b’no’ at Sat Apr 24 07:19:55 2010"

Client received: b"Echo=>b’yellow!’ at Sat Apr 24 07:19:55 2010"

Теперь, когда мы достигли понимания принципов работы основной модели, перейдем к рассмотрению некоторых хитростей. Реализация сценария сервера, организующего ветвление, достаточно проста, но следует сказать несколько слов об использовании некоторых библиотечных инструментов.

Использованная литература:

Марк Лутц — Программирование на Python, 4-е издание, II том, 2011

Каталог сайтов Всего.ру
Оцените статью
Секреты программирования
Добавить комментарий