Встроенный модуль socket в Python представляет функциональность для взаимодействия по сети. Этот модуль определяет низкоуровневый интерфейс для отправки и получения запросов в виде класса socket. И вне зависимости, что мы создаем - программу сервера или клиента, для отправки запросов нам надо создать объект сокета:
import socket sock = socket.socket()
После окончания работы с сокетом его следует закрыть с помощью метода close()
import socket client = socket.socket() client.close()
Дальнейшие действия с сокетом зависят от того, какой именно сокет мы создаем - для сервера или для клиента. В данном случае мы рассмотрим создание простейшего клиента на сокетах Python.
Для подключения к серверу применяется метод connect()
socket.connect(address)
В качестве параметра он получает адрес сервера. Адрес обычно представляется в виде кортежа
(host, port)
Первый элемент - хост в виде строки. Это может быть, например, IP-адрес в виде "127.0.0.1" или название локального хоста. Второй параметр - числовой номер порта. Порт представляет 2-х байтное значение от 0 до 65535. Например:
import socket client = socket.socket() # подключаемся по адресу www.python.org и порту 80 client.connect(("www.python.org", 80)) print("Connected...") client.close() # закрываем подключение
Здесь пытаемся подключиться по адресу "www.python.org" и порту 80. То есть фактически мы пытаемся подключиться к обычному веб-сайту www.python.org
,
который работает на порту 80 (обычно веб-сервер запускается на порту 80). После подключения просто выводим строку на консоль и закрывает сокет.
После установки соединения мы можем отправлять и получать данные от сервера. Для отправки данных применяется метод socket.send(), который в качестве параметра получает набор отправляемых данных.
socket.send(bytes)
Для получения данных у сокета применяется метод socket.recv()
bytes = socket.recv(bufsize[, flags])
В качестве обязательного параметра он принимает максимальный размер буфера в байтах, которые могут быть получены за раз от другого сокета. Размер буфера лучше делать кратным 2, например, 512, 1024 и т.д. Возвращаемое значение - набор байтов, полученых от другого сокета.
Например, отправим данные на сервер "www.python.org" и получим от него ответ:
import socket client = socket.socket() # подключаемся по адресу www.python.org и порту 80 client.connect(("www.python.org", 80)) # данные для отправки - стандартные заголовки протокола http message = "GET / HTTP/1.1\r\nHost: www.python.org\r\nConnection: close\r\n\r\n" print("Connecting...") client.send(message.encode()) # отправляем данные серверу data = client.recv(1024) # получаем данные с сервера print("Server sent: ", data.decode()) # выводим данные на консоль client.close() # закрываем подключение
В данном случае отправляется строка со стандартными заголовками протокола HTTP, которые пониманиет веб-сайт.
Формат запроса HTTP включает прежде всего линию запроса ("GET / HTTP/1.1\r\nHost: www.python.org
), которая состоит из типа запроса, пути к запрошенному ресурсу и
специфической версии протокола. То есть здесь в сообщении мы указываем, что отправляется запрос типа GET по пути "/" (то есть к корню сайта www.python.org").
При этом применяется протокол HTTP/1.1. Линия запроса должна завершаться двойным набором символов каретки и перевода строки \r\n.
Кроме того, запрос HTTP может содержать заголовки. Так, в данном случае отправляем заголовок "Host", который указывает на адрес хоста. В данном случае это "www.python.org:80". И также в данном случае отправляем заголовок "Connection", который имеет значение "close" - это значение предписывает серверу закрыть подключение.
Поскольку мы можем послать только байты, а не строки, то при отправке переводим строку в набор байтов. Для этого применяется метод encode(),
который возвращает объект класса bytes
client.send(message.encode())
После отправки серверу сообщения пытаемся получить от него данные с помощью метода recv()
. При этом буфер для получаемых данных будет иметь размер в 1024 байта. Результат
метода - полученные данные. Однако сокет получает данные в виде набора байт (точнее объекта bytes
). Чтобы их преобразовать в строку, применяется метод
decode():
data = client.recv(1024) # получаем данные с сервера print("Server sent: ", data.decode()) # выводим данные на консоль
И если мы запустим данную программу на Python, то получим ответ напродобие следующего:
Connected... Server sent: HTTP/1.1 301 Moved Permanently Connection: close Content-Length: 0 Server: Varnish Retry-After: 0 Location: https://www.python.org/ Accept-Ranges: bytes Date: Tue, 02 May 2023 17:52:32 GMT Via: 1.1 varnish X-Served-By: cache-bma1653-BMA X-Cache: HIT X-Cache-Hits: 0 X-Timer: S1683049953.637569,VS0,VE0 Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Сервер также нам присылает строку в http-заголовками, которые указывают, что веб-сайт переехал на адрес https://www.python.org/.