9.11. Socket-objektit

Python-rajapinta kuljetuskerrokseen on socket.socket-luokka. Socket edustaa verkkokeskustelun yhtä päätepistettä – osoitetta, porttia ja protokollaa (UDP tai TCP), jonka yli keskustelu kulkee. Laitteistonohjausluvut avasivat UART-instansseja keskustellakseen johdolla; tämä osio avaa socket-instansseja keskustellakseen verkossa. Muoto on sama; pohjalla oleva palvelu on vain paljon kyvykkäämpi.

9.11.1. Socketin luominen

Kolme argumenttia kuvaa socketin: minkä osoiteperheen (address family) se puhuu, minkä socket-tyypin se tarjoaa ja mitä protokollaa se käyttää. Oletukset kattavat tapaukset, joita tämän osion loppuosa käyttää:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)   # IPv4 TCP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    # IPv4 UDP

Kaksi vakiota, joiden välillä sovellus valitsee lähes joka tapauksessa:

Kolmas argumentti (protokolla) jätetään nollaan, mikä valitsee oikean oletuksen kahden ensimmäisen perusteella. Täydellinen konstruktori on dokumentoitu kohdassa socket — socket-moduuli.

9.11.2. Socketin osoitteet

Socket-osoite on monikko (host, port)

("192.168.1.50", 80)
("0.0.0.0", 8000)

Host on IP-osoite merkkijonona. Portti on 16-bittinen kokonaisluku, joka käsitellään kohdassa Portit.

Muutama erityinen host-merkkijono kannattaa tuntea:

  • "0.0.0.0" tarkoittaa ”jokaista IPv4-rajapintaa tällä laitteella”. Tähän osoitteeseen sidottu palvelin hyväksyy yhteyksiä mihin tahansa osoitteeseen, joka kameralla on.

  • "127.0.0.1" on localhost – siihen suuntautuva liikenne ei koskaan poistu laitteesta. Hyödyllinen testaukseen.

  • "255.255.255.255" on paikallinen yleislähetysosoite (broadcast). Siihen lähetetty UDP-datagrammi menee jokaiselle paikallissegmentin laitteelle.

Verkkotunnukset kuten "example.com" eivät ole kelvollisia host-merkkijonoja socket-osoitteessa. Ne täytyy ensin selvittää IP-osoitteeksi; Nimet ja DNS käsittelee sen tekevän getaddrinfo()-kutsun.

9.11.3. Kaksi roolia

Socketin elinkaari riippuu siitä, kummalla puolella keskustelua se on. Asiakassocket kutsuu connect()-metodia (tai UDP:n tapauksessa pelkkää sendto()-metodia) keskustellakseen tunnetun palvelimen kanssa. Palvelinsocket kutsuu bind()-metodia varatakseen portin, sitten joko listen()- ja accept()-metodeja (TCP:lle) tai recvfrom()-metodia (UDP:lle) vastaanottaakseen saapuvaa liikennettä.

Samaa socket-konstruktoria käytetään molemmissa tapauksissa; vain jälkikäteen kutsutut metodit eroavat. Seuraavat kolme sivua käyvät läpi käytännön mallit:

9.11.4. Socketin sulkeminen

Jokainen socket pitää hallussaan pientä käyttöjärjestelmän tilaa (porttivaraus, puskurit, yhteyden TCP-tila). Kun sovellus on valmis sen kanssa, close() vapauttaa tuon tilan. Unohdettu socket on hidas vuoto, joka kertyy; silmukassa, joka avaa yhteyksiä, close-kutsun puuttuminen lopulta tyhjentää kameran käytettävissä olevien socketien varannon.

Siistein malli on with-lause:

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(addr)
    s.send(b"GET / HTTP/1.0\r\n\r\n")
    ...
# socket is closed automatically here, even on error

Socketit toteuttavat kontekstinhallintaprotokollan, joka käsitellään Python-yleiskatsauksessa, joten with-lohko takaa, että close() kutsutaan riippumatta siitä, poistuiko lohko normaalisti vai poikkeuksen nostamalla.

9.11.5. socket-viite

Tämä ja seuraavat sivut käyvät rajapinnan läpi kerronnallisessa muodossa. Jokaisen metodin, jokaisen lipun ja jokaisen moduulin tarjoaman vakion täydellinen argumenttitason viite löytyy kohdasta socket — socket-moduuli. Viite on myös paikka, josta etsiä harvinaisempia toimintoja (socket-asetukset, multicast-ryhmäjäsenyys, IPv6-laajuustunnisteet), joita tämä osio ei käsittele.