ГЛАВА 16. КЛИЕНТ-СЕРВЕРНОЕ ПРОГРАММИРОВАНИЕ В PYTHON

Python содержит стандартные модули, позволяющие обратиться к удаленному вебсерверу по протоколу прикладного уровня HTTP, например:

Переменная conn является объектом класса HTTPResponse, метод read предоставляет информацию о веб-странице, status содержит код статуса HTTP-ответа.

Python заранее не знает, что будет передаваться по сети, поэтому используется специальный тип данных bytes (байтовые строки):

Следующая команда, выполненная в командной строке, запускает локальный веб-сервер на порту 8000:

$ python -m http.server

Предположим, что необходимо передать данные от ПК1 (клиента) к ПК (серверу), расположенным в одной сети:

Для идентификации ПК в сети применяются IP-адреса, например, 192.168.0.3. На ПК работает большое число сетевых приложений (Skype, Telegram и пр.), поэтому, чтобы ПК определить, для какого приложения поступили данные, необходимо каждому сетевому приложению присвоить уникальный номер – сетевой порт (например, Skype использует 80 и 443 порты). Связка «IP-адрес, сетевой порт» называется сокетом (socket). Сокеты предоставляют программный интерфейс для сетевого взаимодействия. Впервые они были реализованы на языке Си в системе BSD. Python имеет встроенный модуль socket .

Сетевое взаимодействие происходит посредством клиент-серверного обмена данными, где клиент – запрашивает (отправляет) данные, сервер – обрабатывает данные, полученные от клиента. Например, веб-клиентом является браузер, а веб-сервером – удаленный ПК, способный обрабатывать HTTP-запросы, поступающие от браузера.

Рассмотрим пример серверного и клиентского приложений, написанных на языке Python. Важно, чтобы клиент и сервер запускались в разных экземплярах IDLE, т.е. IDLE необходимо запустить два раза и в отдельном окне сначала запустить программу-сервер, а затем в другом окне запустить программу-клиента.

Клиент-серверное взаимодействие в нашем примере будет происходить на одном и том же ПК, поэтому в качестве IP-адрес указываем 127.0.0.1.

Сервер (обрабатывает поступающие запросы от клиента):

import socket # подключаем модуль для взаимодействия по сети
HOST = ‘127.0.0.1’ # IP-адрес для клиент-серверного обмена на одном ПК
PORT = 50007 # порт идентифицирует программу-сервер на данном ПК
# создается программный сокет с гарантированной (SOCK_STREAM)
# доставкой данных (протокол TCP):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# сокет привязывается (bind) к IP-адресу и сетевому порту для того,
# чтобы обрабатывать поступающие запросы:
s.bind((HOST, PORT))
# сервер слушает (listen), ожидает входные соединения от клиента:
s.listen(1)
# в момент, когда от клиента поступил запрос на соединение, вызывается
# метод accept, который приводит к созданию нового сокета
#(записывается в переменную conn). Данную операцию можно сравнить с
# поступлением телефонного звонка на коммутатор (listen), который
# перенаправляет звонок к конкретному оператору (accept) и снова
# переходит в режим ожидания:
conn, addr = s.accept() # в переменной addr IP-адрес клиента
print(‘Connected client’)
while 1:
data = conn.recv(1024) # получение данных от клиента, 1024 байт
if not data:
break
else:
print(‘Received[2]: ‘, data)
conn.send(data) # отправка данных клиенту
print(‘Send[3]: ‘, data)
conn.close() # закрытие соединения

Клиент (устанавливает соединение с сервером):

import socket
HOST = ‘127.0.0.1’ # IP-адрес сервера
PORT = 50007 # порт сервера
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# клиент устанавливает соединение с сервером:
s.connect((HOST, PORT))
data = ‘Hello world’
# обмен по сети происходит в формате bytes, поэтому строку перед
# передачей ее серверу, преобразуем:
s.send(data.encode(‘utf-8’))
print(‘Send[1]: ‘, data)
# получение данных от сервера:
data = s.recv(1024)
s.close()
print(‘Received[4]: ‘, data)

Результат работы программы на стороне сервера:

Результат работы программы на стороне клиента: