Как установить модуль socket python
Перейти к содержимому

Как установить модуль socket python

  • автор:

Низкоуровневый сетевой интерфейс в Python

Модуль socket обеспечивает доступ к интерфейсу сокета BSD. Он доступен во всех современных системах Unix, Windows, MacOS и, возможно, на дополнительных платформах.

Он включает в себя функции создания объекта сокета Socket , который и обрабатывает канал данных, а также функции, связанных с сетевыми задачами, такими как преобразование имени сервера в IP адрес и форматирование данных для отправки по сети.

Примечание. Поведение модуля может зависеть от платформы, поскольку выполняются вызовы API сокетов операционной системы.

Интерфейс Python представляет собой прямую трансляцию системного вызова Unix и интерфейса библиотеки для сокетов в объектно-ориентированный стиль Python. Функция socket.socket() возвращает объект Socket , методы которого реализуют различные системные вызовы сокетов.

Типы параметров функций модуля несколько более высокоуровневые, чем в интерфейсе языка C: как и в случае операций чтения/записи с файлами, распределение буфера при операциях приема данных происходит автоматически, а длина буфера неявно определяется операциями отправки.

Сокеты можно настроить для работы в качестве сервера и прослушивания входящих сообщений или для подключения к другим приложениям в качестве клиента. После подключения обоих концов сокета TCP/IP обмен данными становится двунаправленным.

Пример создания и использования сокетов на примере TCP/IP сервер и клиента.

Этот пример, основанный на стандартной документации библиотеки, принимает входящие сообщения и передает их обратно отправителю. Он начинается с создания сокета TCP/IP, а затем метод sock.bind() используется для связывания сокета с адресом сервера.

Примечание. Для успешного тестирования примера, код клиента и сервера необходимо запускать в разных окнах терминала. Код сервера запускается первым.

TCP/IP сервер.
# test-server.py import socket import sys # создаемTCP/IP сокет sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Привязываем сокет к порту server_address = ('localhost', 10000) print('Старт сервера на <> порт <>'.format(*server_address)) sock.bind(server_address) # Слушаем входящие подключения sock.listen(1) while True: # ждем соединения print('Ожидание соединения. ') connection, client_address = sock.accept() try: print('Подключено к:', client_address) # Принимаем данные порциями и ретранслируем их while True: data = connection.recv(16) print(f'Получено: data.decode()>') if data: print('Обработка данных. ') data = data.upper() print('Отправка обратно клиенту.') connection.sendall(data) else: print('Нет данных от:', client_address) break finally: # Очищаем соединение connection.close() 

Вызов метода sock.listen(1) переводит сокет в режим сервера, а метод sock.accept() ожидает входящего соединения. Целочисленный аргумент у метода .listen — это количество соединений, которые система должна поставить в очередь в фоновом режиме, прежде чем отклонять новых клиентов. В этом примере предполагается, что одновременно будет работать только одно соединение.

Метод sock.accept() возвращает открытое соединение между сервером и клиентом вместе с адресом клиента. На самом деле соединение представляет собой другой сокет на другом порту (назначенный ядром). Данные считываются из соединения с помощью метод sock.recv() и передаются с помощью sock.sendall() .

Когда общение с клиентом завершено, соединение необходимо очистить с помощью sock.close() . В этом примере используется блок try/finally , чтобы гарантировать, что метод sock.close() всегда вызывается, даже в случае ошибки.

Клиентская программа настраивает свой сокет иначе, чем сервер. Вместо привязки к порту и прослушивания он использует метод sock.connect() для подключения сокета непосредственно к удаленному адресу.

TCP/IP клиент.
# test-client.py import socket import sys # СоздаемTCP/IP сокет sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Подключаем сокет к порту, через который прослушивается сервер server_address = ('localhost', 10000) print('Подключено к <> порт <>'.format(*server_address)) sock.connect(server_address) try: # Отправка данных mess = 'Hello Wоrld!' print(f'Отправка: mess>') message = mess.encode() sock.sendall(message) # Смотрим ответ amount_received = 0 amount_expected = len(message) while amount_received  amount_expected: data = sock.recv(16) amount_received += len(data) mess = data.decode() print(f'Получено: data.decode()>') finally: print('Закрываем сокет') sock.close() 

После установления соединения данные могут быть отправлены через сокет с помощью метода sock.sendall() и получены с помощью sock.recv() , как и на сервере. Когда все сообщения отправлены, а копия получена, то сокет закрывается, чтобы освободить порт.

Работа клиента и сервера вместе.

Клиент и сервер должны запускаться в отдельных окнах терминала, чтобы они могли взаимодействовать друг с другом. Выходные данные сервера показывают входящее соединение и данные, а также ответ, отправленный обратно клиенту.

Старт сервера на localhost порт 10000 Ожидание соединения. Подключено к: ('127.0.0.1', 34800) Получено: Hello Wоrld! Обработка данных. Отправка обратно клиенту. Получено: Нет данных от: ('127.0.0.1', 34800) Ожидание соединения. .

Выходные данные клиента показывают исходящее сообщение и ответ сервера.

Подключено к localhost порт 10000 Отправка: Hello Wоrld! Получено: HELLO WоRLD! Закрываем сокет
  • КРАТКИЙ ОБЗОР МАТЕРИАЛА.
  • Советы по программированию сокетов
  • Константы, определяемые модулем socket
  • Семейства сокетов, поддерживаемых модулем socket
  • Функция socket() модуля socket, создает новый сокет
  • Функция create_connection() модуля socket
  • Функция create_server() модуля socket
  • Функция socketpair() модуля socket
  • Функция fromfd() модуля socket
  • Функция fromshare() модуля socket
  • Объект Socket модуля socket
  • Функция close() модуля socket
  • Функция getaddrinfo() модуля socket
  • Функция getfqdn() модуля socket
  • Функция gethostbyname() модуля socket
  • Функция gethostbyname_ex() модуля socket
  • Функция gethostname() модуля socket
  • Функция gethostbyaddr() модуля socket
  • Функция getnameinfo() модуля socket
  • Функция getprotobyname() модуля socket
  • Функция getservbyname() модуля socket
  • Функция getservbyport() модуля socket
  • Функция has_dualstack_ipv6() модуля socket
  • Функции getdefaulttimeout() и setdefaulttimeout() модуля socket
  • Функции CMSG_LEN и CMSG_SPACE модуля socket
  • Функция sethostname() модуля socket
  • Функция if_nameindex() модуля socket
  • Функции if_nametoindex() и if_indextoname модуля socket
  • Функции различных преобразований модуля socket
  • Ошибки и исключения, определяемые модулем socket

Краткий обзор раздела: Модуль socket, сетевой интерфейс в Python

Модуль socket обеспечивает доступ к интерфейсу сокета BSD. Доступен во всех современных системах Unix, Windows, MacOS. Включает в себя функции создания сокета, который и обрабатывает канал данных, а также функций, связанных с сетевыми задачами

Советы по программированию сокетов в Python.

В этом материале будет говорится только о сокетах INET (то есть IPv4) STREAM (т.е. TCP), но они составляют не менее 99% используемых сокетов. От сокета STREAM можно получить лучшую производительность, чем от какого-то другого. Так же приоткроем тайну того, что такое сокет и дадим несколько советов.

Константы, определяемые модулем socket в Python.

Разобранные в материале константы представляют собой семейства адресов и протоколов, используемые для первого аргумента функции socket(), типы сокетов, используемые для второго аргумента этой функции, константы которые могут быть объединены с типами сокетов, и т. д.

Семейства сокетов, поддерживаемых модулем socket в Python.

В зависимости от системы и параметров сборки модуль socket поддерживает различные семейства сокетов.

Функция socket() модуля socket, создает новый сокет в Python.

Функция socket() модуля socket создает новый сокет, используя указанное семейство адресов family, тип сокета type и номер протокола proto.

Функция create_connection() модуля socket в Python.

Функция create_connection() модуля socket подключается к службе TCP, прослушивающей Интернет-адрес address- (host, port) и возвращает объект сокета. Это функция более высокого уровня, чем метод объекта сокета Socket.connect()

Функция create_server() модуля socket в Python.

Функция create_server() модуля socket создает сокет, слушающий TCP/IP подключения, привязанный к адресу address в виде 2-кортеж (host, port) и возвращает объект сокета.

Функция socketpair() модуля socket в Python.

Функция socketpair() модуля socket создает пару подключенных объектов сокета, используя заданное семейство адресов family, тип сокета type и номер протокола proto. Вновь созданные сокеты не наследуются.

Функция fromfd() модуля socket в Python.

Функция fromfd() модуля socket дублирует файловый дескриптор и создает объект сокета из результата. Она редко используется, но может применяться для получения или установки параметров сокета, передаваемого программе в качестве стандартного ввода или вывода

Функция fromshare() модуля socket в Python.

Доступность: Windows. Функция fromshare() модуля socket создает экземпляр сокета из данных data, полученных из метода объекта сокета Socket.share().

Объект Socket модуля socket в Python.

Атрибуты и методы, определяемые объектом Socket. Все методы объекта Socket, за исключением метода .makefile(), соответствуют системным вызовам Unix, применимым к сокетам. Объекты Socket ​​поддерживают протокол диспетчера контекста. Выход из диспетчера контекста эквивалентен вызову функции close().

Функция close() модуля socket в Python.

Функция socket.close() похожа на os.close(), но предназначена для сокетов. На некоторых платформах функция os.close() не работает для дескрипторов файлов сокетов, особенно это заметно в Windows.

Функция getaddrinfo() модуля socket в Python.

Функция getaddrinfo() модуля socket преобразует аргумент host/port в список из пяти элементных кортежей, которые содержат все необходимые аргументы для создания сокета, подключенного к этой службе.

Функция getfqdn() модуля socket в Python.

Функция getfqdn() модуля socket возвращает полное доменное имя для аргумента name. Если имя name опущено или пусто, то оно интерпретируется как локальный хост.

Функция gethostbyname() модуля socket в Python.

Функция gethostbyname() модуля socket преобразует имя хоста в формат адреса IPv4. Возвращается IPv4-адрес в виде строки, например 127.0.0.1.

Функция gethostbyname_ex() модуля socket в Python.

Функция gethostbyname_ex() модуля socket преобразует имя хоста/домена в формат адреса IPv4, расширенный интерфейс. Функция socket.gethostbyname_ex() возвращает тройной кортеж (hostname, aliaslist, ipaddrlist).

Функция gethostname() модуля socket в Python.

Функция gethostname() модуля socket возвращает строку, содержащую имя хоста/домена компьютера, на котором в настоящее время выполняется интерпретатор Python.

Функция gethostbyaddr() модуля socket в Python.

Функция gethostbyaddr() модуля socket возвращает тройной кортеж (hostname, aliaslist, ipaddrlist). Функция поддерживает как IPv4, так и IPv6 адресацию.

Функция getnameinfo() модуля socket в Python.

Функция getnameinfo() модуля socket преобразует адрес сокета в кортеж (host, port). В зависимости от настроек флагов результат может содержать полное доменное имя или числовое представление адреса на хосте. Точно так же порт может содержать строковое имя порта или числовой номер порта.

Функция getprotobyname() модуля socket в Python.

Функция getprotobyname() модуля socket преобразует имя Интернет-протокола (например, icmp) в константу, подходящую для передачи в качестве (необязательного) третьего аргумента функции socket.socket().

Функция getservbyname() модуля socket в Python.

Функция getservbyname() модуля socket преобразует имя интернет-протокола servicename (например ‘http’) и имя сетевого-протокола protocolname (например ‘tcp’) в номер порта для этой службы.

Функция getservbyport() модуля socket в Python.

Функция getservbyport() модуля socket преобразует номер интернет-порта и имя сетевого-протокола в имя протокола интернета.

Функция has_dualstack_ipv6() модуля socket в Python.

Функция has_dualstack_ipv6() модуля socket возвращает True, если платформа поддерживает создание TCP-сокета, который может обрабатывать соединения IPv4 и IPv6.

Функции getdefaulttimeout() и setdefaulttimeout() модуля socket в Python.

Функция socket.getdefaulttimeout() возвращает тайм-аут по умолчанию в секундах (float) для новых объектов сокета. Функция socket.setdefaulttimeout() устанавливает тайм-аут по умолчанию в секундах (float) для новых объектов сокета.

Функции CMSG_LEN и CMSG_SPACE модуля socket в Python.

Функция socket.CMSG_LEN() возвращает общую длину без завершающего заполнения элемента вспомогательных данных со связанными данными заданной длины. Функция socket.CMSG_SPACE() возвращает размер буфера, необходимый для метода объекта сокета Socket.recvmsg(), чтобы получить элемент вспомогательные и с

Функция sethostname() модуля socket в Python.

Функция sethostname() модуля socket устанавливает новое имя хоста локальной машины, вызывает ошибку OSError, если у программы недостаточно прав.

Функция if_nameindex() модуля socket в Python.

Функция if_nameindex() модуля socket возвращает список кортежей вида (index int, name string), содержащих информацию о сетевом интерфейсе. Функция socket.if_nameindex() возвращает исключение OSError в случае сбоя системного вызова.

Функции if_nametoindex() и if_indextoname модуля socket в Python.

Функция socket.if_nametoindex() возвращает порядковый номер сетевого интерфейса, соответствующий его имени. Функция socket.if_indextoname() возвращает имя сетевого интерфейса, соответствующее его порядковому номеру.

Функции различных преобразований модуля socket в Python.

В разделе рассмотрены функции преобразования порядка байтов 16 и 32-битных целых чисел и функции преобразования IPv4/v6 в упакованный двоичный формат и обратно.

Ошибки и исключения, определяемые модулем socket в Python.

В разделе рассмотрены ошибки и исключения, определяемые модулем socket, а так же возможные причины их возникновения. Исключения: socket.error, socket.herror, socket.gaierror, socket.timeout.

Клиент-серверные приложения

Встроенный модуль 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

Руководство по программированию сокетов на Python. От введения до работающего примера

К концу руководства вы освоите основные функции и методы модуля Python socket, научитесь применять пользовательский класс для отправки сообщений и данных между конечными точками и работать со всем этим в собственных клиент-серверных приложениях. Материалом делимся к старту курса по Fullstack-разработке на Python.

Сеть при этом может быть логической, локальной сетью компьютера или физически подключённой к внешней сети, с собственными подключениями к другим сетям. Очевидный пример — интернет, к которому подключаются через провайдера.

Примеры протестированы на Python 3.10, но подойдёт и версия 3.6 или новее. Исходным код поможет использовать это руководство по максимуму.

Сети и сокеты — большие темы, по которым написаны томá литературы. Если они вам в новинку, переварить терминологию со всеми подробностями может быть трудно. Но с этим руководством всё получится!

История сокетов

История у сокетов давняя. Их применение началось с ARPANET в 1971 году и продолжилось в 1983-м, когда в операционной системе Berkeley Software Distribution (BSD) появился API под названием «сокеты Беркли».

В 1990-х годах вместе со Всемирной паутиной возникло и сетевое программирование. Преимущества сокетов и первых подключаемых сетей применялись не только в веб-серверах и браузерах — широко стали применяться клиент-серверные приложения разных типов и размеров.

Базовые протоколы API сокетов развивались многие годы, появились и новые, а низкоуровневый API остался прежним.

Самые распространённые сегодня приложения с сокетами — это клиент-серверные приложения, где одна сторона действует как сервер и ожидает подключения клиентов. Именно такое приложение вы напишете благодаря руководству. А конкретнее, сосредоточимся на API сокетов для интернет-сокетов. Иногда их называют сокетами Беркли, или сокетами BSD. Есть и сокеты домена Unix, которые используются для взаимодействия между процессами внутри только одного компьютера.

Обзор API сокетов

Вот основные функции и методы этого API:

  • .socket()
  • .bind()
  • .listen()
  • .accept()
  • .connect()
  • .connect_ex()
  • .send()
  • .recv()
  • .close()

Кроме того, в стандартной библиотеке Python есть классы, которые упрощают применение этих функций. Хотя в этом руководстве socketserver не рассматривается, с этим фреймворком для сетевых серверов можно ознакомиться по ссылке.

Доступно много модулей, где реализованы интернет-протоколы уровня выше, например HTTP и SMTP. Обзор этих протоколов смотрите в разделе документации Python «Интернет-протоколы и их поддержка».

TCP-сокеты

С помощью socket.socket() вы создадите объект сокета с указанием типа сокета socket.SOCK_STREAM . При этом по умолчанию применяется протокол управления передачей (TCP). Возможно, это то, что вам нужно.

Но зачем вам TCP? Вот его особенности:

  • TCP надёжен. Отброшенные в сети пакеты обнаруживаются и повторно передаются отправителем.
  • Данные доставляются с сохранением порядка очерёдности. В приложении данные считываются в порядке их записи отправителем.

Сетевые устройства — маршрутизаторы и коммутаторы — также обладают конечной полосой пропускания и собственными, системными ограничениями. Как на клиентах и на серверах, у них есть процессоры, память, шины и интерфейсные буферы пакетов. С TCP при этом не нужно беспокоиться о потере пакетов, поступлении данных с изменением порядка очерёдности пакетов данных, а также о других подводных камнях.

Чтобы разобраться лучше, ознакомьтесь с последовательностью вызовов API сокетов и с потоком данных TCP.

Ниже слева сервер, а справа клиент:

Поток TCP-сокетов

Поток TCP-сокетов. В центре изображения показан обмен данными между клиентом и сервером с помощью вызовов .send() и .recv() .

Внизу соответствующие сокеты закрываются на клиенте и на сервере. (источник изображения)

Начиная с верхнего левого угла, показаны серверные вызовы API на сервере, которые настраивают «прослушиваемый» сокет:

  • socket()
  • .bind()
  • .listen()
  • .accept()

А чтобы установить подключение к серверу и инициировать трёхэтапное рукопожатие, на клиенте вызывается .connect() . Процесс рукопожатия важен, ведь он гарантирует доступность каждой стороны подключения в сети, то есть то, что клиент может связаться с сервером, и наоборот. Возможно, только один хост, клиент или сервер может связаться с другим.

Эхо-клиент и эхо-сервер

Теперь, когда вы узнали об API сокетов и взаимодействии клиента и сервера, вы готовы создать свои первые клиент и сервер. Начнём с примера, где полученное сервером сообщение просто возвращается клиенту, как эхо.

Эхо-сервер

# echo-server.py import socket HOST = "127.0.0.1" # Standard loopback interface address (localhost) PORT = 65432 # Port to listen on (non-privileged ports are > 1023) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() conn, addr = s.accept() with conn: print(f"Connected by ") while True: data = conn.recv(1024) if not data: break conn.sendall(data)

Не пытайтесь понять весь код сразу. В этих нескольких строках много чего происходит. И это только отправная точка, здесь можно увидеть базовый сервер в деле. Но что же происходит в вызове нашего API?

С помощью socket.socket() создаётся объект сокета, которым поддерживается тип контекстного менеджера, который используется в операторе with . Вызывать s.close() не нужно:

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: pass # Use the socket object without calling s.close().

Передаваемые в socket() аргументы — это константы, используемые для указания семейства адресов и типа сокетов. AF_INET — это семейство интернет-адресов для IPv4. SOCK_STREAM — это тип сокета для TCP и протокол, который будет использоваться для передачи сообщений в сети.

Метод .bind() применяется для привязки сокета к конкретному сетевому интерфейсу и номеру порта:

# echo-server.py # . with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) # . 

Передаваемые в .bind() значения зависят от семейства адресов сокета. В этом примере используется socket. AF_INET (IPv4). Поэтому принимается кортеж с двумя значениями: (host, port) .

host может быть именем хоста, IP-адресом или пустой строкой. Если используется IP-адрес, то host должен быть строкой адреса формата IPv4. IP-адрес 127.0.0.1 — это стандартный IPv4-адрес для интерфейса «внутренней петли», когда к серверу подключаются только процессы в хосте. Если передавать пустую строку, подключения на сервере принимаются во всех доступных интерфейсах IPv4.

port — это номер TCP-порта для приёма подключений от клиентов. Это должно быть целое число от 1 до 65535 ( 0 резервируется). В некоторых системах, если номер порта меньше 1024 , могут потребоваться привилегии суперпользователя.

Относительно использования имён хостов с .bind() есть замечание:

«Если в хостовой части адреса сокета IPv4/v6 использовать имя хоста, программа может стать непредсказуемой: Python использует первый возвращаемый из разрешения DNS адрес. Адрес сокета будет разрешён в фактический адрес IPv4/v6 по-разному, в зависимости от результатов из DNS-разрешения и/или конфигурации хоста. Чтобы поведение было предсказыемым, в хостовой части используйте числовой адрес». Документация.

Подробнее об этом вы узнаете позже в разделе «Использование имён хостов». А пока достаточно понять, что при использовании имени хоста можно увидеть разные результаты в зависимости от того, чтó возвращается в процессе разрешения имён. Это может быть что угодно: при первом запуске приложения можно получить 10.1.2.3 , а в следующий раз получится 192.168.0.1 . Дальше может быть 172.16.7.8 и т. д.

В примере ниже подключения на сервере принимаются благодаря .listen() , а сам сервер становится «прослушиваемым» сокетом:

# echo-server.py # . with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() conn, addr = s.accept() # . 

У метода .listen() есть параметр backlog . Он указывает число непринятых подключений, которые система разрешит до отклонения новых подключений. С версии Python 3.5 он необязателен. Если его нет, выбирается значение backlog по умолчанию.

А если на сервере получается много одновременных запросов на подключение, значение backlog можно увеличить через установку максимальной длины очереди для отложенных подключений. Это предельное значение зависит от системы. Например, на Linux смотрите /proc/sys/net/core/somaxconn .

Методом .accept() выполнение блокируется, и ожидается входящее подключение. При подключении клиента возвращается новый объект сокета, который представляет собой подключение и кортеж с адресом клиента. В кортеже содержится (host, port) — для подключений IPv4 или (host, port, flowinfo, scopeid) — для IPv6. Подробнее о значениях кортежей рассказывается в справочном разделе «Семейства адресов сокетов».

Итак, теперь у вас есть новый объект сокета из .accept() . Это важно потому, что сокет будет использоваться для взаимодействия с клиентом. Он отличается от прослушиваемого, который применяется на сервере для приёма новых подключений:

# echo-server.py # . with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() conn, addr = s.accept() with conn: print(f"Connected by ") while True: data = conn.recv(1024) if not data: break conn.sendall(data)

После того как в .accept() клиенту предоставляется объект сокета conn , для перебора блокирующих вызовов в conn.recv() используется бесконечный цикл while . Так любые отправляемые от клиента данные считываются и передаются обратно с помощью conn.sendall() .

Если в conn.recv() возвращается пустой объект bytes и b» , значит, в клиенте подключение закрыто и цикл завершён. Чтобы автоматически закрыть сокет в конце блока, с conn применяется оператор with .

Эхо-клиент

Перейдём к клиенту:

# echo-client.py import socket HOST = "127.0.0.1" # The server's hostname or IP address PORT = 65432 # The port used by the server with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) s.sendall(b"Hello, world") data = s.recv(1024) print(f"Received ")

По сравнению с сервером клиент довольно прост. В нём создаётся объект сокета. Для подключения к серверу используется .connect() , и для отправки сообщения вызывается s.sendall() , s.recv() считывает ответ, а затем этот ответ выводится.

Запуск эхо-клиента и эхо-сервера

В этом разделе запускаем клиент и сервер, следим за их поведением и за происходящим.

> Если вам не удаётся запустить из командной строки примеры или собственный код, прочитайте How Do I Make My Own Command-Line Commands Using Python? или How to Run Your Python Scripts (англ.). Если у вас Windows, ознакомьтесь с Python Windows FAQ («Часто задаваемыми вопросами по Python для Windows»).

Откройте терминал или командную строку, перейдите в каталог со скриптами, убедитесь, что в переменной PATH у вас есть Python 3.6 или новее, а затем запустите сервер:

$ python echo-server.py 

Терминал зависнет, потому что сервер заблокирован или находится в состоянии ожидания, в .accept() :

# echo-server.py # . with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() conn, addr = s.accept() with conn: print(f"Connected by ") while True: data = conn.recv(1024) if not data: break conn.sendall(data)

Ожидается подключение клиента. Затем откройте другое окно терминала или командную строку и запустите клиента:

$ python echo-client.py Received b'Hello, world'

В окне сервера вы должны заметить что-то такое:

$ python echo-server.py Connected by ('127.0.0.1', 64623)

Здесь на сервере выведен кортеж addr , возвращаемый из s.accept() . Это IP-адрес клиента и номер TCP-порта — 64623 (скорее всего, он будет другим, когда вы запустите сервер на своём компьютере).

Просмотр состояния сокета

Чтобы увидеть текущее состояние сокетов на хосте, используйте netstat . На macOS, Linux и Windows он доступен по умолчанию.

А ниже вывод netstat из macOS после запуска сервера:

$ netstat -an Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 127.0.0.1.65432 *.* LISTEN

Обратите внимание: Local Address здесь 127.0.0.1.65432 . Если бы в echo-server.py был HOST = «» , а не HOST = «127.0.0.1» , в netstat отображалось бы это:

$ netstat -an Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 *.65432 *.* LISTEN

Local Address здесь *.65432 . Это означает, что для приёма входящих подключений будут задействованы все поддерживающие семейство адресов доступные интерфейсы хоста. В этом примере в вызове socket() используется socket. AF_INET (IPv4) — смотрите tcp4 в столбце Proto .

Здесь показывается только вывод эхо-сервера. Скорее всего, полный вывод будет гораздо больше, это зависит вашей системы. Стóит обратить внимание на столбцы Proto , Local Address и (state) . В последнем примере netstat показывает, что на эхо-сервере используется TCP-сокет IPv4 ( tcp4 ) в порте 65432 на всех интерфейсах ( *.65432 ) и он находится в состоянии прослушивания ( LISTEN ).

Другой способ получить к нему доступ (и дополнительную полезную информацию) — использовать программу lsof , которая выводит список открытых файлов. На macOS она доступна по умолчанию, а на Linux её можно установить пакетным менеджером:

$ lsof -i -n COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME Python 67982 nathan 3u IPv4 0xecf272 0t0 TCP *:65432 (LISTEN)

Если lsof используется с параметром -i , в её выводе предоставляется COMMAND , PID (идентификатор процесса) и USER (идентификатор пользователя) открытых интернет-сокетов. Выше показан процесс эхо-сервера.

netstat и lsof различаются в зависимости от ОС, у них много опций. Загляните в их man или документацию, на них определённо стóит потратить немного времени. На macOS и Linux используйте man netstat и man lsof . На Windows — netstat /? .

При попытке подключения к порту без прослушиваемого сокета есть типичная ошибка:

$ python echo-client.py Traceback (most recent call last): File "./echo-client.py", line 9, in s.connect((HOST, PORT)) ConnectionRefusedError: [Errno 61] Connection refused

Здесь либо указан неверный номер порта, либо не запускается сервер. Или, может быть, на пути стоит брандмауэр, которым подключение блокируется (об этом легко забыть). Также может быть сообщение об ошибке Connection timed out («Превышено время ожидания подключения»). Чтобы клиент подключался к TCP-порту, добавьте соответствующее правило брандмауэра!

  • Профессия Fullstack-разработчик на Python (15 месяцев)
  • Профессия Data Scientist (24 месяца)

Краткий каталог курсов

  • Профессия Data Scientist
  • Профессия Data Analyst
  • Курс «Математика для Data Science»
  • Курс «Математика и Machine Learning для Data Science»
  • Курс по Data Engineering
  • Курс «Machine Learning и Deep Learning»
  • Курс по Machine Learning
  • Профессия Fullstack-разработчик на Python
  • Курс «Python для веб-разработки»
  • Профессия Frontend-разработчик
  • Профессия Веб-разработчик
  • Профессия iOS-разработчик
  • Профессия Android-разработчик
  • Профессия Java-разработчик
  • Профессия QA-инженер на JAVA
  • Профессия C#-разработчик
  • Профессия Разработчик игр на Unity
  • Курс «Алгоритмы и структуры данных»
  • Профессия C++ разработчик
  • Профессия «Белый хакер»
  • Курс по DevOps
  • Все курсы

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *