9.11. Об’єкти сокетів#
Інтерфейс Python до транспортного рівня – це клас socket.socket. Сокет представляє один кінець мережевої розмови – адресу, порт і протокол (UDP або TCP), по якому ведеться розмова. У розділах з апаратного керування відкривалися екземпляри UART для спілкування по проводу; цей розділ відкриває екземпляри socket для спілкування по мережі. Форма та сама; базовий сервіс просто набагато потужніший.
9.11.1. Створення сокета#
Три аргументи описують сокет: яке сімейство адрес він підтримує, який тип сокета пропонує та який протокол використовує. Значення за замовчуванням охоплюють випадки, що розглядаються в решті цього розділу:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # IPv4 TCP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # IPv4 UDP
Дві константи, між якими застосунок обирає майже в кожному випадку:
AF_INET– адреси IPv4 (числовий IP плюс порт). Найпоширеніший вибір.AF_INET6– еквівалент для IPv6.SOCK_STREAM– TCP-з’єднання, надійний потік байтів.SOCK_DGRAM– еквівалент для UDP.
Третій аргумент (протокол) залишається рівним нулю, що автоматично вибирає правильне значення за замовчуванням на основі перших двох. Повна документація конструктора знаходиться в socket — модуль сокетів.
9.11.2. Адреси сокета#
Адреса сокета – це кортеж (host, port)
("192.168.1.50", 80)
("0.0.0.0", 8000)
Хост – це IP-адреса у вигляді рядка. Порт – це 16-бітне ціле число, розглянуте на сторінці Порти.
Варто знати кілька спеціальних рядків хоста:
"0.0.0.0"означає «кожен IPv4-інтерфейс на цьому пристрої». Сервер, прив’язаний до цієї адреси, приймає з’єднання на будь-якій адресі, яку має камера."127.0.0.1"– це localhost – трафік до нього ніколи не покидає пристрій. Корисно для тестування."255.255.255.255"– адреса локального широкомовного розсилання. UDP-датаграма, надіслана на неї, потрапляє на кожен пристрій у локальному сегменті.
Доменні імена типу "example.com" не є допустимими рядками хоста в адресі сокета. Їх спочатку потрібно перетворити на IP-адресу; сторінка Імена та DNS описує виклик getaddrinfo(), який це робить.
9.11.3. Дві ролі#
Життєвий цикл сокета залежить від того, яку сторону розмови він займає. Клієнтський сокет викликає connect() (або, для UDP, просто sendto()) для спілкування з відомим сервером. Серверний сокет викликає bind() для отримання порту, потім listen() і accept() (для TCP) або recvfrom() (для UDP) для отримання вхідного трафіку.
В обох випадках використовується той самий конструктор socket; відрізняються лише методи, що викликаються після. Наступні три сторінки розповідають про практичні шаблони:
UDP-сокети – надсилання та отримання датаграм.
TCP-сокети – TCP-клієнт і сервер.
Сокети з asyncio – все вищезазначене, але всередині циклу подій
asyncio.
9.11.4. Закриття сокета#
Кожен сокет займає невелику частину стану операційної системи (резервування порту, буфери, TCP-стан з’єднання). Коли застосунок закінчує роботу з ним, close() звільняє цей стан. Забутий сокет – це повільний витік ресурсів, який накопичується; в циклі, що відкриває з’єднання, відсутність close врешті-решт вичерпає пул доступних сокетів камери.
Найчистіший шаблон – оператор with
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(addr)
s.send(b"GET / HTTP/1.0\r\n\r\n")
...
# socket is closed automatically here, even on error
Сокети реалізують протокол контекстного менеджера, розглянутий у загальному огляді Python, тому блок with гарантує виклик close() незалежно від того, чи блок завершився нормально, чи через виняток.
9.11.5. Довідник socket#
Ця та наступні сторінки описують API у розповідній формі. Повний довідник на рівні аргументів для кожного методу, кожного прапора і кожної константи, що надається модулем, дивіться в socket — модуль сокетів. Довідник також є місцем для пошуку менш поширених операцій (параметри сокета, членство в групах multicast, ідентифікатори областей IPv6), які цей розділ не охоплює.