Сетевое программирование в Python: сокеты и продвинутые протоколы
Два уровня доступа к сетевым службам
Python предоставляет два уровня доступа к сетевым службам. На низком уровне можно обращаться к базовой поддержке сокетов в базовой операционной системе, что позволяет реализовывать клиенты и серверы для протоколов, ориентированных на соединение, и без соединения.
Python также имеет библиотеки для высокоуровневого доступа к конкретным прикладным сетевым протоколам: FTP, HTTP и др.
Эта глава дает понимание самой известной концепции в сетях — программирования сокетов.
Что такое сокеты?
Сокеты — это конечные точки двунаправленного канала связи. Сокеты могут обмениваться данными внутри процесса, между процессами на одной машине или между процессами на разных континентах.
Сокеты могут быть реализованы над разными типами каналов: сокеты домена Unix, TCP, UDP и др. Библиотека socket предоставляет специальные классы для обработки распространенных транспортов и общий интерфейс для остальных.
Терминология сокетов
| № | Термин и описание |
|---|---|
| 1 | Domain (Семейство) — семейство протоколов, используемое как транспортный механизм. Константы: AF_INET, PF_INET, PF_UNIX, PF_X25 и др. |
| 2 | type — тип связи между двумя конечными точками. Обычно SOCK_STREAM для ориентированных на соединение протоколов и SOCK_DGRAM для безсоединенных. |
| 3 | protocol — обычно ноль, может идентифицировать вариант протокола в домене и типе. |
| 4 | hostname — идентификатор сетевого интерфейса:
|
| 5 | port — каждый сервер слушает клиентов на одном или нескольких портах. Порт может быть номером (Fixnum), строкой с номером или именем службы. |
Модуль socket
Для создания сокета используется функция socket.socket() из модуля socket:
s = socket.socket(socket_family, socket_type, protocol=0)
Параметры:
socket_family —
AF_UNIXилиAF_INET.socket_type —
SOCK_STREAMилиSOCK_DGRAM.protocol — обычно опускается, по умолчанию 0.
После получения объекта socket можно использовать необходимые функции для создания клиента или сервера.
Методы серверного сокета
| № | Метод и описание |
|---|---|
| 1 | s.bind() — привязывает адрес (hostname, порт) к сокету. |
| 2 | s.listen() — настраивает и запускает TCP-слушатель. |
| 3 | s.accept() — пассивно принимает TCP-соединение клиента, блокируясь до прибытия соединения. |
Методы клиентского сокета
| № | Метод и описание |
|---|---|
| 1 | s.connect() — активно инициирует TCP-соединение с сервером. |
Общие методы сокета
| № | Метод и описание |
|---|---|
| 1 | s.recv() — получает TCP-сообщение. |
| 2 | s.send() — отправляет TCP-сообщение. |
| 3 | s.recvfrom() — получает UDP-сообщение. |
| 4 | s.sendto() — отправляет UDP-сообщение. |
| 5 | s.close() — закрывает сокет. |
| 6 | socket.gethostname() — возвращает имя хоста. |
Простой сервер
Для написания интернет-серверов используем функцию socket из модуля socket для создания объекта сокета. Затем настраиваем сервер.
Вызываем bind(hostname, port) для указания порта сервиса на данном хосте.
Затем вызываем метод accept возвращенного объекта. Этот метод ждет подключения клиента к указанному порту и возвращает объект connection, представляющий соединение с этим клиентом.
#!/usr/bin/python
# server.py
import socket
s = socket.socket() # Создание объекта сокета
host = socket.gethostname() # Получение локального имени машины
port = 12345 # Резервирование порта для сервиса
s.bind((host, port)) # Привязка к порту
s.listen(5) # Ожидание подключения клиента
while True:
c, addr = s.accept() # Установление соединения с клиентом
print('Got connection from', addr)
c.send('Thank you for connecting')
c.close() # Закрытие соединения
Простой клиент
Напишем простой клиент, открывающий соединение с портом 12345 на данном хосте. Создание клиента с помощью модуля socket очень просто.
socket.connect(hostname, port) открывает TCP-соединение с hostname на port. Получив открытый сокет, можно читать из него как из любого IO-объекта. Не забывайте закрывать его, как файл.
#!/usr/bin/python
# client.py
import socket
s = socket.socket() # Создание объекта сокета
host = socket.gethostname() # Получение локального имени машины
port = 12345 # Резервирование порта для сервиса
s.connect((host, port))
print(s.recv(1024))
s.close() # Закрытие сокета
Запуск:
# Запуск сервера в фоне
$ python server.py &
# Запуск клиента
$ python client.py
Результат:
Got connection from ('127.0.0.1', 48437)
Thank you for connecting
Модули Python для Интернета
Список важных модулей в сетевом/интернет-программировании Python:
| Протокол | Общая функция | Порт | Python-модуль |
|---|---|---|---|
| HTTP | Веб-страницы | 80 | httplib, urllib, xmlrpclib |
| NNTP | Новости Usenet | 119 | nntplib |
| FTP | Передача файлов | 20 | ftplib, urllib |
| SMTP | Отправка почты | 25 | smtplib |
| POP3 | Получение почты | 110 | poplib |
| IMAP4 | Получение почты | 143 | imaplib |
| Telnet | Командные строки | 23 | telnetlib |
| Gopher | Передача документов | 70 | gopherlib, urllib |
Проверьте все упомянутые библиотеки для работы с FTP, SMTP, POP и IMAP.
Дополнительное чтение
Это был быстрый старт с программированием сокетов. Тема обширна. Рекомендуется изучить:
- Unix Socket Programming.
- Python Socket Library and Modules.
Python
- Освоение типов данных в Python: практическое руководство
- Мастерство операторов Python: Полное руководство
- Оператор pass в Python: практическое руководство
- Аргументы функций в Python: позиционные, именованные и параметры по умолчанию
- Словари в Python: создание, манипуляции и продвинутые техники
- Объектно-ориентированное программирование в Python: классы, наследование, инкапсуляция и полиморфизм
- Итераторы в Python: как они работают и как создать свои
- Замыкания в Python: как вложенные функции захватывают переменные
- Модуль datetime в Python: практическое руководство по датам, времени и часовым поясам
- Освоение Python time.sleep(): лучшие практики, многопоточность и реальные примеры