Модуль socket
Работа с сокетами
Функции
getaddrinfo
Функция getaddrinfo(host, port, af=0, type=0, proto=0, flags=0)
Преобразует аргументы host
и port
в последовательность 5-кортежей, содержащих все необходимые аргументы для создания сокета, подключённого к этому сервису. Аргументы af
, type
и proto
(которые имеют то же значение, что и в функции socket()
) могут использоваться для фильтрации адресов, которые будут возвращены. Если параметр не указан или равен нулю, возвращаются все возможные комбинации адресов (требуется фильтрация результатов со стороны пользователя).
Результирующий список из 5-кортежей имеет следующую структуру:
(family, type, proto, canonname, sockaddr)
Следующий пример показывает, как выполнить подключение к указанному URL:
s = socket.socket()
# Предполагается, что если "type" не указан, будет возвращён
# адрес для SOCK_STREAM — это может быть неверным.
addr = socket.getaddrinfo('telematic.dev', 80)[0][-1]
s.connect(addr)
Рекомендуемый способ использования с параметрами фильтрации:
s = socket.socket()
# Гарантированно вернёт адрес, подходящий для connect с целью
# поточной (stream) работы.
addr = socket.getaddrinfo('telematic.dev', 80, 0, SOCK_STREAM)[0][-1]
s.connect(addr)
Отличие от CPython В случае ошибки в этой функции CPython генерирует исключение
socket.gaierror
(подклассOSError
).
MicroPython вместо этого генерирует исключениеOSError
напрямую. Обратите внимание, что номера ошибок, возвращаемыхgetaddrinfo()
, находятся в отдельном пространстве имён и могут не совпадать с номерами ошибок из модуляerrno
. Чтобы отличить ошибкиgetaddrinfo()
, они представлены отрицательными номерами. В то же время стандартные системные ошибки имеют положительные значения (номера ошибок доступны через свойствоe.args[0]
из объекта исключения).
gethostbyname
Функция gethostbyname(hostname)
возвращает IPv4 адрес хоста/домена hostname
в формат строки.
Если имя хоста hostname является IPv4-адресом, то оно возвращается без изменений.
Функция gethostbyname()
не поддерживает разрешение имен IPv6-адресов, для поддержки двойного стека IPv4/v6 следует использовать функцию socket.getaddrinfo()
.
from net import gethostbyname
print(gethostbyname('ya.ru')) # 77.88.44.242
print(gethostbyname('google.com')) # 173.194.221.100
Классы
socket
Класс socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP)
является основным элементом для работы с сетевыми интерфейсами.
Сокет можно создать для работы как с TCP, так и с UDP соединениями.
Аргументы:
family
(опционально): Указывает семейство протоколов. Возможные значения:socket.AF_INET
— IPv4 (по умолчанию).socket.AF_INET6
— IPv6 (поддержка зависит от реализации).
type
(опционально): Указывает тип сокетов. Возможные значения:socket.SOCK_STREAM
— Транспорт TCP (по умолчанию).socket.SOCK_DGRAM
— Транспорт UDP.
Указание proto
в большинстве случаев не требуется. Вместо этого параметр type
выбирает нужный протокол автоматически:
# Создать TCP-сокет поточного типа (STREAM)
socket(AF_INET, SOCK_STREAM)
# Создать UDP-сокет датаграммного типа (DGRAM)
socket(AF_INET, SOCK_DGRAM)
Метод bind(address)
привязывает сокет к указанному сетевому адресу.
address
— Кортеж(host, port)
, гдеhost
— IP-адрес устройства (или пустая строка""
для всех интерфейсов), аport
— номер порта.
s = socket.socket()
s.bind(('0.0.0.0', 8080))
Метод listen(backlog)
переводит сокет в режим “сервер”, чтобы принимать входящие соединения (только для TCP).
backlog
— Максимальное количество ожидающих подключений.
s.listen(5)
Метод accept()
ожидает входящее соединение и возвращает (conn, address)
:
conn
— Новый сокет для взаимодействия с клиентом.address
— Адрес клиента в формате(host, port)
.
conn, addr = s.accept()
print('Новое соединение от:', addr)
Метод connect(address)
устанавливает соединение с сервером.
address
— Кортеж(host, port)
, гдеhost
— IP-адрес сервера, аport
— номер порта.
s.connect(('192.168.1.10', 8080))
Метод send(data)
отправляет данные через соединение (для TCP).
data
— Байтовая строка для отправки.
s.send(b'Hello, server!')
Метод sendto(data, address)
отправляет данные через соединение UDP.
data
— Байтовая строка для отправки.address
— Кортеж(host, port)
с адресом получателя.
s.sendto(b'Hello, UDP!', ('192.168.1.10', 12345))
Метод recv(bufsize)
получает данные от сокета.
bufsize
— Размер буфера для приёма данных (в байтах).
data = s.recv(1024)
print('Получено:', data)
Метод recvfrom(bufsize)
получает данные от UDP-сокета.
bufsize
— Размер буфера для приёма данных (в байтах).
Возвращает (data, address)
:
data
— Принятая информация.address
— Адрес отправителя.
data, address = s.recvfrom(1024)
print('Данные от', address, ':', data)
Метод close()
закрывает сокет и освобождает ресурсы.
s.close()
Метод setblocking(flag)
устанавливает режим блокировки сокета.
flag
: ЕслиTrue
(по умолчанию), сокет работает в блокирующем режиме. ЕслиFalse
, операции чтения/записи становятся неблокирующими.
s.setblocking(False)
Метод setsockopt(level, optname, value)
устанавливает параметры сокета.
level
— Уровень протокола (обычноsocket.SOL_SOCKET
).optname
— Параметр настраиваемой опции.value
— Значение опции.
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Константы
Модуль socket
содержит ряд стандартных констант:
-
Типы адресов:
socket.AF_INET
— IPv4.socket.AF_INET6
— IPv6.
-
Типы транспорта:
socket.SOCK_STREAM
— TCP.socket.SOCK_DGRAM
— UDP.
-
Опции для
setsockopt
:socket.SOL_SOCKET
— Уровень настроек сокета.socket.SO_REUSEADDR
— Повторное использование локального адреса.
Примеры
Простой TCP-сервер
import socket
# Создание сокета
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 8080))
s.listen(1) # Максимум 1 подключение
print('Ожидание подключения...')
conn, addr = s.accept()
print('Подключение от:', addr)
# Приём и отправка данных
data = conn.recv(1024) # Приём данных
print('Получено:', data.decode('utf-8'))
conn.send(b'Hello, client!') # Ответ клиенту
conn.close()
s.close()
Простой TCP-клиент
import socket
# Создание сокета
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.10', 8080)) # Подключение к серверу
# Отправка и приём данных
s.send(b'Hello, server!')
data = s.recv(1024)
print('Ответ от сервера:', data.decode('utf-8'))
s.close()
Простой UDP-сервер
import socket
# Создание UDP-сокета
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('0.0.0.0', 8080)) # Привязываем к адресу и порту
print('UDP сервер запущен...')
while True:
data, addr = s.recvfrom(1024)
print('Сообщение от', addr, ':', data.decode('utf-8'))
s.sendto(b'Hello from server!', addr) # Ответ отправителю
Простой UDP-клиент
import socket
# Создание UDP-сокета
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Отправка сообщения
s.sendto(b'Hello, UDP Server!', ('192.168.1.10', 8080))
data, addr = s.recvfrom(1024)
print('Ответ от сервера:', data.decode('utf-8'))
s.close()