socket — modul socket

Tento modul poskytuje přístup k rozhraní BSD socketů.

Rozdíl oproti CPythonu

Z důvodu efektivity a konzistence implementují objekty socketů v MicroPythonu rozhraní stream (souboru podobné) přímo. V CPythonu je nutné převést socket na objekt podobný souboru pomocí metody makefile(). Tato metoda je v MicroPythonu stále podporována (ale je no-op), takže tam, kde záleží na kompatibilitě s CPythonem, ji určitě používejte.

Formát(y) adresy socketu

Nativní formát adresy socketu modulu socket je neprůhledný datový typ vracený funkcí getaddrinfo(), kterou je nutné použít k rozlišení textové adresy (včetně numerických adres):

sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# You must use getaddrinfo() even for numeric addresses
sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1]
# Now you can use that address
sock.connect(sockaddr)

Použití getaddrinfo() je nejefektivnější (jak z hlediska paměti, tak výpočetního výkonu) a přenositelný způsob práce s adresami.

Modul socket rovněž poskytuje způsob kompatibilní s CPythonem pro zadávání adres pomocí n-tic, jak je popsáno níže. Na OpenMV Cam je modul socket zabudovaný; numerické adresy lze zadat přímo ve formátu n-tice, ale doménová jména musí být nejprve rozlišena pomocí getaddrinfo().

Shrnutí:

  • Pro rozlišení názvů hostitelů vždy používejte getaddrinfo().

  • Adresy ve formátu n-tice popsané níže lze použít jako zkratku pro numerické adresy, pro rychlé hacky a interaktivní použití.

Formát adresy ve formátu n-tice pro modul socket:

  • IPv4: (ipv4_address, port), kde ipv4_address je řetězec s numerickou IPv4 adresou v tečkové notaci, např. "8.8.8.8", a port je celočíselné číslo portu v rozsahu 1-65535. Doménová jména nejsou jako ipv4_address přijímána; nejprve je rozlište pomocí getaddrinfo().

  • IPv6: (ipv6_address, port, flowinfo, scopeid), kde ipv6_address je řetězec s numerickou IPv6 adresou v dvojtečkové notaci, např. "2001:db8::1", a port je celočíselné číslo portu v rozsahu 1-65535. flowinfo musí být 0. scopeid je identifikátor rozsahu rozhraní pro link-local adresy. Doménová jména nejsou jako ipv6_address přijímána; nejprve je rozlište pomocí getaddrinfo().

Funkce

socket.getaddrinfo(host: str, port: int, af: int = 0, type: int = 0, proto: int = 0, flags: int = 0, /) List[Tuple]

Přeloží argument host/port na sekvenci 5-tic, které obsahují všechny argumenty potřebné pro vytvoření socketu připojeného k dané službě. Argumenty af, type a proto (které mají stejný význam jako u funkce socket) lze použít k filtrování, jaký druh adres je vracen. Pokud parametr není zadán nebo je nulový, mohou být vraceny všechny kombinace adres (vyžadující filtrování na straně uživatele).

Výsledný seznam 5-tic má následující strukturu:

(family, type, proto, canonname, sockaddr)

Následující příklad ukazuje, jak se připojit k dané url:

s = socket.socket()
# This assumes that if "type" is not specified, an address for
# SOCK_STREAM will be returned, which may be not true
s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1])

Doporučené použití filtrovacích parametrů:

s = socket.socket()
# Guaranteed to return an address which can be connect'ed to for
# stream operation.
s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1])

Rozdíl oproti CPythonu

CPython vyvolá v případě chyby v této funkci výjimku socket.gaierror (podtřídu OSError). MicroPython nemá socket.gaierror a vyvolá přímo OSError. Pozor, čísla chyb funkce getaddrinfo() tvoří samostatný jmenný prostor a nemusí odpovídat číslům chyb z modulu errno. K odlišení chyb getaddrinfo() jsou tyto reprezentovány zápornými čísly, zatímco standardní systémové chyby jsou čísla kladná (čísla chyb jsou dostupná pomocí vlastnosti e.args[0] z objektu výjimky). Použití záporných hodnot je prozatímní detail, který se v budoucnu může změnit.

socket.inet_ntop(af: int, bin_addr: bytes) str

Převede binární síťovou adresu bin_addr dané adresní rodiny af na textovou reprezentaci:

>>> socket.inet_ntop(socket.AF_INET, b"\x7f\0\0\1")
'127.0.0.1'
socket.inet_pton(af: int, txt_addr: str) bytes

Převede textovou síťovou adresu txt_addr dané adresní rodiny af na binární reprezentaci:

>>> socket.inet_pton(socket.AF_INET, "1.2.3.4")
b'\x01\x02\x03\x04'

Konstanty

socket.AF_INET: int

Adresní rodina IPv4.

socket.AF_INET6: int

Adresní rodina IPv6.

socket.SOCK_STREAM: int

Typ socketu stream (TCP).

socket.SOCK_DGRAM: int

Typ socketu datagram (UDP).

socket.SOCK_RAW: int

Typ socketu raw.

socket.IPPROTO_IP: int

Úroveň protokolu IP. Používá se jako argument level metody setsockopt() společně s volbami IP_*.

socket.IPPROTO_TCP: int

Protokol TCP. Není nutné jej předávat do socket (typ socketu SOCK_STREAM jej vybere automaticky); jeho jediné skutečné využití je jako argument level metody setsockopt() společně s volbami TCP_*.

socket.SOL_SOCKET: int

Úroveň voleb socketu. Používá se jako argument level metody setsockopt() společně s volbami SO_*.

socket.SO_REUSEADDR: int

Umožní socketu navázat se na adresu/port, který je stále ve stavu TIME_WAIT.

socket.SO_BROADCAST: int

Povolí odesílání datagramů na broadcastovou adresu.

socket.SO_KEEPALIVE: int

Povolí periodické vysílání keep-alive sond na připojeném socketu.

socket.SO_SNDTIMEO: int

Časový limit odesílání v milisekundách, předaný jako argument value metodě setsockopt().

socket.SO_RCVTIMEO: int

Časový limit příjmu v milisekundách, předaný jako argument value metodě setsockopt().

socket.IP_ADD_MEMBERSHIP: int

Připojí se k multicastové skupině. Volba setsockopt() úrovně IPPROTO_IP.

socket.IP_DROP_MEMBERSHIP: int

Opustí multicastovou skupinu. Volba setsockopt() úrovně IPPROTO_IP.

socket.TCP_NODELAY: int

Zakáže Nagleho algoritmus. Volba setsockopt() úrovně IPPROTO_TCP.

socket.MSG_PEEK: int

Pro recv() / recvfrom(): vrátí data bez jejich odstranění ze vstupní fronty.

socket.MSG_DONTWAIT: int

Pro recv() / recvfrom(): provede operaci v neblokujícím režimu.

Třídy

class socket.socket(af: int = AF_INET, type: int = SOCK_STREAM, proto: int = IPPROTO_TCP, /)

Vytvoří nový socket s použitím dané adresní rodiny, typu socketu a čísla protokolu. Zadání proto ve většině případů není vyžadováno (a není doporučováno); argument type vybere potřebný protokol automaticky:

# Create STREAM TCP socket
socket(AF_INET, SOCK_STREAM)
# Create DGRAM UDP socket
socket(AF_INET, SOCK_DGRAM)
close() None

Označí socket jako uzavřený a uvolní všechny prostředky. Jakmile k tomu dojde, všechny budoucí operace s objektem socketu selžou. Vzdálený konec obdrží indikaci EOF, pokud to protokol podporuje.

Sockety jsou automaticky uzavírány při garbage collection, ale doporučuje se close() je explicitně, jakmile s nimi dokončíte práci.

bind(address: Any) None

Naváže socket na address. Socket nesmí být již navázán.

listen(backlog: int = 2) None

Umožní serveru přijímat připojení. Pokud je zadán backlog, musí být alespoň 0 (pokud je nižší, bude nastaven na 0); a určuje počet nepřijatých připojení, který systém povolí před odmítnutím nových připojení. Pokud není zadán, je zvolena výchozí rozumná hodnota.

accept() Tuple['socket', Tuple]

Přijme připojení. Socket musí být navázán na adresu a naslouchat připojením. Návratovou hodnotou je dvojice (conn, address), kde conn je nový objekt socketu použitelný pro odesílání a příjem dat na tomto připojení a address je adresa navázaná na socket na druhém konci připojení.

connect(address: Any) None

Připojí se ke vzdálenému socketu na address.

send(bytes: bytes) int

Odešle data na socket. Socket musí být připojen ke vzdálenému socketu. Vrací počet odeslaných bajtů, který může být menší než délka dat („short write“).

sendall(bytes: bytes) None

Odešle všechna data na socket. Socket musí být připojen ke vzdálenému socketu. Na rozdíl od send() se tato metoda pokusí odeslat všechna data tím, že je odesílá postupně po částech.

Chování této metody na neblokujících socketech není definováno. Z tohoto důvodu se v MicroPythonu doporučuje místo toho používat metodu write(), která má stejnou politiku „no short writes“ pro blokující sockety a u neblokujících socketů vrátí počet odeslaných bajtů.

recv(bufsize: int, flags: int = 0) bytes

Přijme data ze socketu. Návratovou hodnotou je objekt typu bytes reprezentující přijatá data. Maximální množství dat přijatých najednou je určeno parametrem bufsize.

Volitelný argument flags je bitový OR příznaků zprávy (MSG_PEEK, MSG_DONTWAIT), které mají stejný význam jako v CPythonu.

sendto(bytes: bytes, address: Any) int

Odešle data na socket. Socket by neměl být připojen ke vzdálenému socketu, protože cílový socket je určen parametrem address.

recvfrom(bufsize: int, flags: int = 0) Tuple[bytes, Tuple]

Přijme data ze socketu. Návratovou hodnotou je dvojice (bytes, address), kde bytes je objekt typu bytes reprezentující přijatá data a address je adresa socketu odesílajícího data.

Vysvětlení volitelného argumentu flags viz funkce recv().

setsockopt(level: int, optname: int, value: int | bytes) None

Nastaví hodnotu dané volby socketu. Potřebné symbolické konstanty jsou definovány v modulu socket (SO_* atd.). value může být celé číslo nebo objekt podobný bytes reprezentující buffer.

settimeout(value: float | None) None

Nastaví časový limit pro blokující operace socketu. Argument value může být nezáporné desetinné číslo vyjadřující sekundy, nebo None. Pokud je zadána nenulová hodnota, následující operace socketu vyvolají výjimku OSError, pokud hodnota časového limitu uplyne dříve, než byla operace dokončena. Pokud je zadána nula, socket je uveden do neblokujícího režimu. Pokud je zadáno None, socket je uveden do blokujícího režimu.

Přenositelnou a obecnou alternativou je použít objekt select.poll. To umožňuje čekat na více objektů současně (a nejen na sockety, ale na obecné objekty stream, které podporují polling). Příklad:

# Instead of:
s.settimeout(1.0)  # time in seconds
s.read(10)  # may timeout

# Use:
poller = select.poll()
poller.register(s, select.POLLIN)
res = poller.poll(1000)  # time in milliseconds
if not res:
    # s is still not ready for input, i.e. operation timed out

Rozdíl oproti CPythonu

CPython vyvolá v případě vypršení časového limitu výjimku socket.timeout, která je podtřídou OSError. MicroPython místo toho vyvolá přímo OSError. Pokud k zachycení výjimky použijete except OSError:, váš kód bude fungovat v MicroPythonu i v CPythonu.

setblocking(flag: bool) None

Nastaví blokující nebo neblokující režim socketu: pokud je flag false, socket je nastaven na neblokující, jinak na blokující režim.

Tato metoda je zkratkou pro určitá volání settimeout():

  • sock.setblocking(True) je ekvivalentní sock.settimeout(None)

  • sock.setblocking(False) je ekvivalentní sock.settimeout(0)

makefile(mode: str = 'rb', buffering: int = 0, /) Any

Vrátí objekt souboru asociovaný se socketem. Přesný vrácený typ závisí na argumentech předaných do makefile(). Podpora je omezena pouze na binární režimy (‚rb‘, ‚wb‘ a ‚rwb‘). Argumenty CPythonu encoding, errors a newline nejsou podporovány.

Rozdíl oproti CPythonu

Protože MicroPython nepodporuje bufferované streamy, hodnota parametru buffering je ignorována a považována za 0 (bez bufferování).

Rozdíl oproti CPythonu

Uzavření objektu souboru vráceného metodou makefile() uzavře TAKÉ původní socket.

read(size: int | None = None) bytes

Načte ze socketu až size bajtů. Vrátí objekt typu bytes. Pokud size není zadán, načte všechna data dostupná ze socketu až do EOF; jako taková se metoda nevrátí, dokud není socket uzavřen. Tato funkce se pokusí načíst tolik dat, kolik je požadováno (žádné „short reads“). U neblokujícího socketu to však nemusí být možné, a pak bude vráceno méně dat.

readinto(buf: bytearray | memoryview, nbytes: int | None = None) int

Načte bajty do buf. Pokud je zadán nbytes, načte nanejvýš tolik bajtů. Jinak načte nanejvýš len(buf) bajtů. Stejně jako read() se tato metoda řídí politikou „no short reads“.

Návratová hodnota: počet bajtů načtených a uložených do buf.

readline() bytes

Načte řádek zakončený znakem nového řádku.

Návratová hodnota: načtený řádek.

write(buf: bytes) int

Zapíše buffer bajtů na socket. Tato funkce se pokusí zapsat všechna data na socket (žádné „short writes“). U neblokujícího socketu to však nemusí být možné a vrácená hodnota bude menší než délka buf.

Návratová hodnota: počet zapsaných bajtů.

Poznámka

MicroPython neimplementuje socket.error. CPython má zastaralou výjimku socket.error, která je aliasem OSError; v MicroPythonu k zachycení chyb souvisejících se sockety použijte přímo OSError.