Python socket send timeout

Примечания к тайм-аутам розеток

Объект сокета может находиться в одном из трех режимов: блокирующий, неблокирующий или время ожидания. Сокеты по умолчанию всегда создаются в режиме блокировки, но это можно изменить, вызвав setdefaulttimeout() .

  • В режиме блокировки операции блокируются до завершения или система не возвращает ошибку (например, истекло время ожидания соединения).
  • В неблокирующем режиме операции завершаются неудачно (с ошибкой, которая, к сожалению, зависит от системы), если они не могут быть выполнены немедленно: функции из select можно использовать, чтобы узнать, когда и доступен ли сокет для чтения или записи.
  • В режиме тайм-аута операции завершаются ошибкой, если они не могут быть завершены в течение тайм-аута, указанного для сокета (они вызывают исключение timeout ) или если система возвращает ошибку.

На уровне операционной системы сокеты в режиме ожидания внутренне устанавливаются в неблокирующий режим. Кроме того, режимы блокировки и тайм-аута являются общими для файловых дескрипторов и объектов сокетов, которые ссылаются на одну и ту же конечную точку сети. Эта деталь реализации может иметь видимые последствия, если, например, вы решите использовать fileno() сокета.

Тайм-ауты и метод connect

Операция connect() также зависит от настройки тайм-аута, и обычно рекомендуется вызывать settimeout() перед вызовом connect() или передавать параметр тайм-аута в create_connection() . Однако системный сетевой стек также может возвращать собственную ошибку тайм-аута соединения независимо от любого параметра тайм-аута сокета Python.

Тайм-ауты и метод accept

Если getdefaulttimeout() не None , сокеты, возвращаемые методом accept() , наследуют это время ожидания. В противном случае поведение зависит от настроек прослушивающего сокета:

  • если прослушивающий сокет находится в режиме блокировки или в режиме ожидания , сокет, возвращаемый accept() , находится в режиме блокировки ;
  • если прослушивающий сокет находится в неблокирующем режиме , то, находится ли сокет, возвращаемый accept() , в блокирующем или неблокирующем режиме, зависит от операционной системы. Если вы хотите обеспечить межплатформенное поведение, рекомендуется вручную переопределить этот параметр.
Читайте также:  Python работа с seaborn

Example

Вот четыре минимальных примера программ, использующих протокол TCP/IP: сервер, который повторяет все данные, которые он получает обратно (обслуживая только одного клиента), и клиент, использующий его. Обратите внимание, что сервер должен выполнять последовательность socket() , bind() , listen() , accept() (возможно, повторяя accept() для обслуживания более чем одного клиента), в то время как клиенту нужна только последовательность socket() , connect() . Также обратите внимание, что сервер не sendall() / recv() для сокета, который он прослушивает, а для нового сокета, возвращенного accept() .

Первые два примера поддерживают только IPv4.

# Программа эхо-сервера import socket HOST = '' # Символьное имя, обозначающее все доступные интерфейсы PORT = 50007 # Произвольный непривилегированный порт with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen(1) conn, addr = s.accept() with conn: print('Connected by', addr) while True: data = conn.recv(1024) if not data: break conn.sendall(data)
# Клиентская программа Echo import socket HOST = 'daring.cwi.nl' # Удаленный хост PORT = 50007 # Тот же порт, что и сервер 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('Received', repr(data))

Следующие два примера идентичны вышеуказанным,но поддерживают как IPv4,так и IPv6.Серверная сторона будет прослушивать первое доступное семейство адресов (вместо них она должна прослушивать оба).На большинстве готовых к использованию IPv6 систем приоритет будет отдан IPv6,и сервер может не принимать трафик IPv4.Клиентская сторона попытается подключиться ко всем адресам,возвращаемым в результате разрешения имен,и отправит трафик на первый успешно подключенный.

# Программа эхо-сервера import socket import sys HOST = None # Символьное имя, обозначающее все доступные интерфейсы PORT = 50007 # Произвольный непривилегированный порт s = None for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): af, socktype, proto, canonname, sa = res try: s = socket.socket(af, socktype, proto) except OSError as msg: s = None continue try: s.bind(sa) s.listen(1) except OSError as msg: s.close() s = None continue break if s is None: print('could not open socket') sys.exit(1) conn, addr = s.accept() with conn: print('Connected by', addr) while True: data = conn.recv(1024) if not data: break conn.send(data)
# Клиентская программа Echo import socket import sys HOST = 'daring.cwi.nl' # Удаленный хост PORT = 50007 # Тот же порт, что и сервер s = None for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res try: s = socket.socket(af, socktype, proto) except OSError as msg: s = None continue try: s.connect(sa) except OSError as msg: s.close() s = None continue break if s is None: print('could not open socket') sys.exit(1) with s: s.sendall(b'Hello, world') data = s.recv(1024) print('Received', repr(data))

Следующий пример показывает,как написать очень простой сетевой сниффер с сырыми сокетами под Windows.В примере требуются права администратора для изменения интерфейса:

import socket # публичный сетевой интерфейс HOST = socket.gethostbyname(socket.gethostname()) # создать необработанный сокет и привязать его к общедоступному интерфейсу s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP) s.bind((HOST, 0)) # Включить заголовки IP s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) #принимать все пакеты s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON) #получить пакет print(s.recvfrom(65565)) # отключен неразборчивый режим s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)

Следующий пример показывает,как использовать интерфейс сокета для связи с сетью CAN,используя протокол сырых сокетов.Чтобы вместо этого использовать CAN с протоколом менеджера вещания,откройте сокет с:

socket.socket(socket.AF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM)

После привязки ( CAN_RAW ) или подключения ( CAN_BCM ) сокета вы можете использовать socket.send() и socket.recv() (и их аналоги) для объекта сокета, как обычно.

Читайте также:  Jquery elements to javascript

Этот последний пример может потребовать особых привилегий:

import socket import struct # Упаковка / распаковка CAN кадра (см. 'Struct can_frame' в ) can_frame_fmt = "=IB3x8s" can_frame_size = struct.calcsize(can_frame_fmt) def build_can_frame(can_id, data): can_dlc = len(data) data = data.ljust(8, b'\x00') return struct.pack(can_frame_fmt, can_id, can_dlc, data) def dissect_can_frame(frame): can_id, can_dlc, data = struct.unpack(can_frame_fmt, frame) return (can_id, can_dlc, data[:can_dlc]) # создаем необработанный сокет и привязываем его к интерфейсу 'vcan0' s = socket.socket(socket.AF_CAN, socket.SOCK_RAW, socket.CAN_RAW) s.bind(('vcan0',)) while True: cf, addr = s.recvfrom(can_frame_size) print('Received: can_id=%x, can_dlc=%x, data=%s' % dissect_can_frame(cf)) try: s.send(cf) except OSError: print('Error sending CAN frame') try: s.send(build_can_frame(0x01, b'\x01\x02\x03')) except OSError: print('Error sending CAN frame')

Запуск примера несколько раз со слишком малой задержкой между исполнениями может привести к этой ошибке:

OSError: [Errno 98] Address already in use

Это связано с тем, что предыдущее выполнение оставило сокет в TIME_WAIT и не может быть немедленно повторно использовано.

Существует socket флаг набора для того, чтобы предотвратить это, socket.SO_REUSEADDR :

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((HOST, PORT))

SO_REUSEADDR флаг сообщает ядро повторно использовать локальный сокет в TIME_WAIT состоянии, не дожидаясь ее естественным истечение таймаута.

Введение в программирование сокетов (на C)см.в следующих документах:

  • Вводное руководство по межпроцессному взаимодействию 4.3BSD от Стюарта Сехреста
  • Advanced 4.3BSD Interprocess Communication Tutorial , автор: Samuel J. Leffler и др.,

как в Руководстве программиста UNIX, Дополнительные документы 1 (разделы PS1:7 и PS1:8). Справочные материалы по различным системным вызовам, связанным с сокетами, также являются ценным источником информации о деталях семантики сокетов. Для Unix обратитесь к страницам руководства; для Windows см. спецификацию WinSock (или Winsock 2). Для готовых к IPv6 API читатели могут обратиться к RFC 3493 , озаглавленному «Базовые расширения интерфейса сокетов для IPv6».

Источник

Оцените статью