socket — modulul socket

Acest modul oferă acces la interfața de socket BSD.

Diferențe față de CPython

Pentru eficiență și consecvență, obiectele socket din MicroPython implementează direct o interfață stream (de tip fișier). În CPython, trebuie să convertiți un socket într-un obiect de tip fișier folosind metoda makefile(). Această metodă este în continuare acceptată de MicroPython (dar nu are efect), deci acolo unde contează compatibilitatea cu CPython, asigurați-vă că o folosiți.

Format(e) de adresă socket

Formatul nativ de adresă socket al modulului socket este un tip de date opac returnat de funcția getaddrinfo(), care trebuie folosită pentru a rezolva adrese textuale (inclusiv adrese numerice):

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)

Folosirea getaddrinfo() este modul cel mai eficient (atât din punct de vedere al memoriei, cât și al puterii de procesare) și portabil de a lucra cu adrese.

Modulul socket oferă, de asemenea, o modalitate compatibilă cu CPython de a specifica adrese folosind tupluri, așa cum se descrie mai jos. Pe OpenMV Cam, modulul socket este integrat; adresele numerice pot fi date direct în format de tuplu, dar numele de domeniu trebuie mai întâi rezolvate cu getaddrinfo().

Pe scurt:

  • Folosiți întotdeauna getaddrinfo() pentru a rezolva numele de gazdă.

  • Adresele de tip tuplu descrise mai jos pot fi folosite ca o scurtătură pentru adresele numerice, pentru improvizații rapide și utilizare interactivă.

Format de adresă tuplu pentru modulul socket:

  • IPv4: (ipv4_address, port), unde ipv4_address este un șir cu o adresă IPv4 numerică în notație cu puncte, de ex. "8.8.8.8", iar port este un număr întreg de port în intervalul 1-65535. Numele de domeniu nu sunt acceptate ca ipv4_address; rezolvați-le mai întâi folosind getaddrinfo().

  • IPv6: (ipv6_address, port, flowinfo, scopeid), unde ipv6_address este un șir cu o adresă IPv6 numerică în notație cu două puncte, de ex. "2001:db8::1", iar port este un număr întreg de port în intervalul 1-65535. flowinfo trebuie să fie 0. scopeid este identificatorul de domeniu de aplicare al interfeței pentru adresele link-local. Numele de domeniu nu sunt acceptate ca ipv6_address; rezolvați-le mai întâi folosind getaddrinfo().

Funcții

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

Traduce argumentul gazdă/port într-o secvență de 5-tupluri care conțin toate argumentele necesare pentru crearea unui socket conectat la acel serviciu. Argumentele af, type și proto (care au aceeași semnificație ca pentru funcția socket) pot fi folosite pentru a filtra ce tip de adrese sunt returnate. Dacă un parametru nu este specificat sau este zero, pot fi returnate toate combinațiile de adrese (necesitând filtrare din partea utilizatorului).

Lista rezultată de 5-tupluri are următoarea structură:

(family, type, proto, canonname, sockaddr)

Exemplul următor arată cum să vă conectați la o adresă url dată:

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])

Utilizare recomandată a parametrilor de filtrare:

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])

Diferențe față de CPython

CPython generează o excepție socket.gaierror (subclasă a OSError) în caz de eroare în această funcție. MicroPython nu are socket.gaierror și generează direct OSError. Rețineți că numerele de eroare ale getaddrinfo() formează un spațiu de nume separat și este posibil să nu corespundă cu numerele de eroare din modulul errno. Pentru a distinge erorile getaddrinfo(), acestea sunt reprezentate prin numere negative, în timp ce erorile standard de sistem sunt numere pozitive (numerele de eroare sunt accesibile folosind proprietatea e.args[0] dintr-un obiect excepție). Folosirea valorilor negative este un detaliu provizoriu care s-ar putea schimba în viitor.

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

Convertește o adresă de rețea binară bin_addr din familia de adrese dată af într-o reprezentare textuală:

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

Convertește o adresă de rețea textuală txt_addr din familia de adrese dată af într-o reprezentare binară:

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

Constante

socket.AF_INET: int

Familia de adrese IPv4.

socket.AF_INET6: int

Familia de adrese IPv6.

socket.SOCK_STREAM: int

Tipul de socket flux (TCP).

socket.SOCK_DGRAM: int

Tipul de socket datagramă (UDP).

socket.SOCK_RAW: int

Tipul de socket brut.

socket.IPPROTO_IP: int

Nivelul protocolului IP. Folosit ca argument level pentru setsockopt() împreună cu opțiunile IP_*.

socket.IPPROTO_TCP: int

Protocolul TCP. Nu trebuie să transmiteți acest lucru către socket (tipul de socket SOCK_STREAM îl selectează automat); singura sa utilizare reală este ca argument level pentru setsockopt() împreună cu opțiunile TCP_*.

socket.SOL_SOCKET: int

Nivelul de opțiuni socket. Folosit ca argument level pentru setsockopt() împreună cu opțiunile SO_*.

socket.SO_REUSEADDR: int

Permite socketului să se lege la o adresă/port care se află încă în starea TIME_WAIT.

socket.SO_BROADCAST: int

Permite trimiterea de datagrame către o adresă de difuzare (broadcast).

socket.SO_KEEPALIVE: int

Activează transmiterea periodică a sondelor keep-alive pe un socket conectat.

socket.SO_SNDTIMEO: int

Timeout de trimitere, în milisecunde, transmis ca argument value către setsockopt().

socket.SO_RCVTIMEO: int

Timeout de primire, în milisecunde, transmis ca argument value către setsockopt().

socket.IP_ADD_MEMBERSHIP: int

Se alătură unui grup multicast. O opțiune setsockopt() la nivel IPPROTO_IP.

socket.IP_DROP_MEMBERSHIP: int

Părăsește un grup multicast. O opțiune setsockopt() la nivel IPPROTO_IP.

socket.TCP_NODELAY: int

Dezactivează algoritmul lui Nagle. O opțiune setsockopt() la nivel IPPROTO_TCP.

socket.MSG_PEEK: int

Pentru recv() / recvfrom(): returnează datele fără a le elimina din coada de intrare.

socket.MSG_DONTWAIT: int

Pentru recv() / recvfrom(): execută operația în mod neblocant.

Clase

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

Creează un nou socket folosind familia de adrese, tipul de socket și numărul de protocol date. Specificarea proto nu este necesară în majoritatea cazurilor (și nu este recomandată); argumentul type selectează automat protocolul necesar:

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

Marchează socketul ca închis și eliberează toate resursele. Odată ce acest lucru se întâmplă, toate operațiile viitoare pe obiectul socket vor eșua. Capătul de la distanță va primi indicația EOF dacă este acceptată de protocol.

Socketurile sunt închise automat atunci când sunt colectate de garbage collector, dar se recomandă să le închideți (close()) explicit imediat ce ați terminat de lucrat cu ele.

bind(address: Any) None

Leagă socketul la address. Socketul nu trebuie să fie deja legat.

listen(backlog: int = 2) None

Permite unui server să accepte conexiuni. Dacă backlog este specificat, trebuie să fie cel puțin 0 (dacă este mai mic, va fi setat la 0); și specifică numărul de conexiuni neacceptate pe care sistemul le va permite înainte de a refuza conexiuni noi. Dacă nu este specificat, este aleasă o valoare implicită rezonabilă.

accept() Tuple['socket', Tuple]

Acceptă o conexiune. Socketul trebuie să fie legat la o adresă și să asculte după conexiuni. Valoarea returnată este o pereche (conn, address) unde conn este un nou obiect socket utilizabil pentru a trimite și primi date pe conexiune, iar address este adresa legată de socketul de la celălalt capăt al conexiunii.

connect(address: Any) None

Se conectează la un socket de la distanță la address.

send(bytes: bytes) int

Trimite date către socket. Socketul trebuie să fie conectat la un socket de la distanță. Returnează numărul de octeți trimiși, care poate fi mai mic decât lungimea datelor („scriere scurtă”).

sendall(bytes: bytes) None

Trimite toate datele către socket. Socketul trebuie să fie conectat la un socket de la distanță. Spre deosebire de send(), această metodă va încerca să trimită toate datele, trimițându-le bucată cu bucată în mod consecutiv.

Comportamentul acestei metode pe socketuri neblocante este nedefinit. Din acest motiv, în MicroPython se recomandă folosirea metodei write() în schimb, care are aceeași politică de „fără scrieri scurte” pentru socketurile blocante și va returna numărul de octeți trimiși pe socketurile neblocante.

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

Primește date de la socket. Valoarea returnată este un obiect bytes care reprezintă datele primite. Cantitatea maximă de date care pot fi primite deodată este specificată de bufsize.

Argumentul opțional flags este un OR pe biți al indicatorilor de mesaj (MSG_PEEK, MSG_DONTWAIT), care au aceeași semnificație ca în CPython.

sendto(bytes: bytes, address: Any) int

Trimite date către socket. Socketul nu trebuie să fie conectat la un socket de la distanță, deoarece socketul de destinație este specificat de address.

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

Primește date de la socket. Valoarea returnată este o pereche (bytes, address) unde bytes este un obiect bytes care reprezintă datele primite, iar address este adresa socketului care trimite datele.

Consultați funcția recv() pentru o explicație a argumentului opțional flags.

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

Setează valoarea opțiunii de socket date. Constantele simbolice necesare sunt definite în modulul socket (SO_* etc.). value poate fi un număr întreg sau un obiect de tip bytes care reprezintă un tampon (buffer).

settimeout(value: float | None) None

Setează un timeout pentru operațiile blocante pe socket. Argumentul value poate fi un număr în virgulă mobilă nenegativ care exprimă secunde, sau None. Dacă este dată o valoare nenulă, operațiile ulterioare pe socket vor genera o excepție OSError dacă perioada de timeout a expirat înainte ca operația să se fi finalizat. Dacă este dat zero, socketul este pus în mod neblocant. Dacă este dat None, socketul este pus în mod blocant.

O alternativă portabilă și generică este folosirea unui obiect select.poll. Acest lucru permite așteptarea pe mai multe obiecte în același timp (și nu doar pe socketuri, ci pe obiecte generice stream care acceptă interogare). Exemplu:

# 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

Diferențe față de CPython

CPython generează o excepție socket.timeout în caz de timeout, care este o subclasă a OSError. MicroPython generează direct un OSError în schimb. Dacă folosiți except OSError: pentru a prinde excepția, codul dumneavoastră va funcționa atât în MicroPython, cât și în CPython.

setblocking(flag: bool) None

Setează modul blocant sau neblocant al socketului: dacă flag este fals, socketul este setat la neblocant, altfel la mod blocant.

Această metodă este o prescurtare pentru anumite apeluri settimeout():

  • sock.setblocking(True) este echivalent cu sock.settimeout(None)

  • sock.setblocking(False) este echivalent cu sock.settimeout(0)

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

Returnează un obiect fișier asociat cu socketul. Tipul exact returnat depinde de argumentele date către makefile(). Suportul este limitat doar la modurile binare («rb», «wb» și «rwb»). Argumentele CPython: encoding, errors și newline nu sunt acceptate.

Diferențe față de CPython

Deoarece MicroPython nu acceptă fluxuri cu buffer, valorile parametrului buffering sunt ignorate și tratate ca și cum ar fi 0 (fără buffer).

Diferențe față de CPython

Închiderea obiectului fișier returnat de makefile() VA închide și socketul original.

read(size: int | None = None) bytes

Citește până la size octeți de la socket. Returnează un obiect bytes. Dacă size nu este dat, citește toate datele disponibile de la socket până la EOF; ca atare, metoda nu va returna până când socketul nu este închis. Această funcție încearcă să citească cât mai multe date posibil (fără „citiri scurte”). Acest lucru poate să nu fie totuși posibil cu un socket neblocant, caz în care vor fi returnate mai puține date.

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

Citește octeți în buf. Dacă nbytes este specificat, atunci citește cel mult atâția octeți. În caz contrar, citește cel mult len(buf) octeți. La fel ca read(), această metodă urmează politica „fără citiri scurte”.

Valoarea returnată: numărul de octeți citiți și stocați în buf.

readline() bytes

Citește o linie, terminată cu un caracter de linie nouă.

Valoarea returnată: linia citită.

write(buf: bytes) int

Scrie tamponul (buffer) de octeți în socket. Această funcție va încerca să scrie toate datele într-un socket (fără „scrieri scurte”). Acest lucru poate să nu fie totuși posibil cu un socket neblocant, caz în care valoarea returnată va fi mai mică decât lungimea lui buf.

Valoarea returnată: numărul de octeți scriși.

Notă

MicroPython nu implementează socket.error. CPython are o excepție socket.error depreciată care este un alias al OSError; în MicroPython, folosiți direct OSError pentru a prinde erorile legate de socket.