Теперь, когда я показал, как писать серверы с применением ветвления или потоков для обслуживания клиентов без блокирования входящих запросов, следует сказать, что в библиотеке Python имеются стандартные инструменты, облегчающие этот процесс. В частности, в модуле socketserver определены классы, реализующие практически все виды серверов, реализующих прием ветвления или использующих потоки выполнения, которые могут вас заинтересовать.
Подобно серверам, созданным вручную, которые мы только что рассмотрели, основные классы в этом модуле реализуют серверы, обеспечивающие одновременное (или асинхронное) обслуживание нескольких клиентов, ликвидируя угрозу отказа в обслуживании новых запросов при выполнении продолжительных операций с другими клиентами. Основное их назначение состоит в том, чтобы автоматизировать реализацию наиболее типичных разновидностей серверов. При использовании этого модуля достаточно просто создать объект сервера нужного импортируемого типа и передать ему объект обработчика с собственным методом обратного вызова, как показано в примере 12.8 реализации многопоточного сервера TCP.
Пример 12.8. PP4E\Internet\Sockets\class-server.py
На стороне сервера: открывает сокет на указанном порту, ожидает поступления сообщения от клиента и отправляет его обратно; эта версия использует стандартный модуль socketserver; модуль socketserver предоставляет классы TCPServer, ThreadingTCPServer, ForkingTCPServer, их варианты для протокола UDP и многое другое, передает каждый запрос клиента на соединение методу handle нового экземпляра указанного объекта обработчика; кроме того, модуль socketserver поддерживает доменные сокеты Unix, но только в Unix-подобных системах; смотрите руководство по стандартной библиотеке Python.
import socketserver, time # получить серверы сокетов, объекты-обработчики myHost = » # компьютер-сервер, » означает локальный хост
myPort = 50007 # использовать незарезервированный номер порта
def now():
return time.ctime(time.time())
class MyClientHandler(socketserver.BaseRequestHandler):
def handle(self): # для каждого клиента
print(self.client_address, now()) # показать адрес этого клиента time.sleep(5) # имитировать блокирующие действия
while True: # self.request — сокет клиента
data = self.request.recv(1024) # чтение, запись в сокет клиента if not data: break reply = ‘Echo=>%s at %s’ % (data, now()) self.request.send(reply.encode())
self.request.close()
# создать сервер с поддержкой многопоточной модели выполнения,
# слушать/обслуживать клиентов непрерывно
myaddr = (myHost, myPort)
server = socketserver.ThreadingTCPServer(myaddr, MyClientHandler) server.serve_forever()
Этот сервер действует так же, как сервер с потоками выполнения, написанный нами вручную в предыдущем разделе, но здесь усилия сосредоточены на реализации услуги (индивидуальной реализации метода handle), а не на деталях поддержки многопоточной модели выполнения. И выполняется он точно так же — ниже приводится результат обработки трех клиентов, созданных вручную, и восьми, порожденных сценарием testecho из примера 12.3:
[окно 1: сервер, serverHost=’localhost’ в echo-client.py]
C:\…\PP4E\Internet\Sockets> python class-server.py
127.0.0.1′, |
59036) |
Sun |
Apr |
25 13:50 |
:23 |
2010 |
127.0.0.1′, |
59037) |
Sun |
Apr |
25 13:50 |
:25 |
2010 |
127.0.0.1′, |
59038) |
Sun |
Apr |
25 13:50 |
:26 |
2010 |
127.0.0.1′, |
59039) |
Sun |
Apr |
25 13:51 |
:05 |
2010 |
127.0.0.1′, |
59040) |
Sun |
Apr |
25 13:51 |
:05 |
2010 |
127.0.0.1′, |
59041) |
Sun |
Apr |
25 13:51 |
:06 |
2010 |
127.0.0.1′, |
59042) |
Sun |
Apr |
25 13:51 |
:06 |
2010 |
127.0.0.1′, |
59043) |
Sun |
Apr |
25 13:51 |
:06 |
2010 |
127.0.0.1′, |
59044) |
Sun |
Apr |
25 13:51 |
:06 |
2010 |
127.0.0.1′, |
59045) |
Sun |
Apr |
25 13:51 |
:06 |
2010 |
127.0.0.1′, |
59046) |
Sun |
Apr |
25 13:51 |
:06 |
2010 |
[окна 2-4: клиент, тот же компьютер]
C:\…\PP4E\Internet\Sockets> python echo-client.py
Client received: b"Echo=>b’Hello network world’ at Sun Apr 25 13:50:28 2010"
C:\…\PP4E\Internet\Sockets> python echo-client.py localhost Arthur
Client received: b"Echo=>b’Arthur’ at Sun Apr 25 13:50:30 2010"
C:\…\PP4E\Internet\Sockets> python echo-client.py localhost Brave
Sir Robin
Client received: b"Echo=>b’Brave’ at Sun Apr 25 13:50:31 2010"
Client received: b"Echo=>b’Sir’ at Sun Apr 25 13:50:31 2010"
Client received: b"Echo=>b’Robin’ at Sun Apr 25 13:50:31 2010"
C:\…\PP4E\Internet\Sockets> python testecho.py
Чтобы создать ветвящийся сервер, достаточно при создании объекта сервера просто использовать имя класса ForkingTCPServer. Модуль socketserver является более мощным, чем может показаться из данного примера: он поддерживает также непараллельные (последовательные или синхронные) серверы, UDP и доменные сокеты Unix и прерывание работы серверов комбинацией клавиш Ctrl—C в Windows. Подробности ищите в руководстве по библиотеке Python.
Для удовлетворения более сложных потребностей в составе стандартной библиотеки Python имеются также инструменты, которые используют представленные здесь серверы и позволяют в нескольких строках реализовать простой, но полнофункциональный сервер HTTP, который знает, как запускать серверные CGI-сценарии. Мы исследуем эти инструменты в главе 15.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011