A Python programozási nyelv

Hálózatkezelés

A Python alacsony és magas szinten is biztosítja a hálózati kommunikáció megvalósítására alkalmazott eszközöket. Alacsony szinten az operációs rendszer által nyújtott alapvető szolgáltatásokat használja ki, ami lehetővé teszi a szerver és kliens alkalmazások számára mind a kapcsolatorientált, mind a kapcsolatnélküli protokollok használatát. Magasabb szintű eszközöket támogató programkönyvtárai olyan alkalmazásszintű hálózati protokollokat támogatnak, mint az FTP, HTTP stb.

A socket modul

A Python socket modulja hozzáférést biztosít az általános BSD socket interfészhez, amely az összes modern operációs rendszeren megtalálható alacsonyszintű szolgáltatásokat tartalmaz, pl. Unix rendszereken, Windows-on, Mac OS X-en stb. A modul az objektumorientált átírását valósítja meg a Unix socket-kezelési mechanizmusainak: a socket() hívás egy socket objektummal tér vissza, amelynek metódusain keresztül a standard socket műveleteket hajthatjuk végre, ugyanakkor, a rendszerszintű eljárásoknál összetettebb feladatokra is képes, pl. automatikus memória-allokáció.

Socket létrehozása

Egy socket létrehozására a socket() hívást használhatjuk, melynek általános szintaxisa a következő:

s = socket.socket (socket_family, socket_type, protocol=0)

ahol

socket_family: A kommunikáció során használt címzés-család. Értékei konstansok, pl.
socket.AF_INET (IPV4 protokoll, TCP és UDP egyaránt)
socket.AF_INET6 (IPV4 protokoll, TCP és UDP egyaránt)
socket.PF_UNIX (UNIX protokoll) stb.
socket_type: A két végpont közötti adatátvitel típusa socket.SOCK_STREAM: kapcsolatorientált kommunikáció kezdeményezésére socket.SOCK_DGRAM: datagram alapú kommunikáció kezdeményezésére
protocol: A socketen belüli protokollok meghatározása.Normális esetben egy protokollcsaládon belül egy protokollt használunk, így az alapértelmezett érték 0 - elhagyható.

A socketen végezhető általános műveletek

bind() Címet (host – port pár) kapcsol egy sockethez
listen() Figyeli a bejövő kapcsolatfelvételi kérelmeket
accept() Elfogadja a kapcsolatfelvételt, vár a kommunikáció megkezdéséig
connect() Létrehoz egy kapcsolatobjektumot
send() TCP üzenetet küld
recv() TCP üzenetet fogad
sendto() UDP üzenetet küld
recvfrom() UDP üzenetet fogad
close() Zárja a socketet

Egyszerű szerver példa

import socket # socket modul importalasa   s = socket.socket() # socket objektum letrehozasa host = socket.gethostname() # lokalis gep nevenek elkerese port = 12345 # a port meghatarozasa s.bind((host, port)) # porthoz torteno bind   s.listen(5) # figyeles megkezdese while True c, addr = s.accept() print 'Connection:', addr # kapcsolat letrehozasa a klienssel c.send('Hello') c.close() # kapcsolat zarasa

Egyszerű kliens példa

import socket # socket modul importalasa s = socket.socket() # socket objektum letrehozasa host = socket.gethostname() # lokalis gep nevenek elkerese port = 12345 # a port meghatarozasa s.connect((host, port)) # kapcsolodas a szerverhez print s.recv(1024) s.close # kapcsolat zarasa

A socketserver modul

A magasabbszintű, hálózati eszközöket támogató modulok egyike, mely leegyszerűsíti a szerverek megvalósítását. Négy alapvető szervertípust különböztetünk meg, melyek osztályai:

TCPServer TCP protokoll használatával folytonos adatátvitelt biztosít a szerver és a kliens között
UDPServer UDP protokoll használatával, azaz az információt diszkrét csomagok formájában szállítva kommunikál (datagram)
UnixStreamServer Unix domain socket-et használó, folytonos kommunikációt biztosító szerver. Csak Unix rendszereken elérhető.
UnixDatagramServer Unix domain socket-et használó, datagram szerver. Csak Unix rendszereken elérhető.

Az osztályok között fennálló hierarchia a következő:

Szerverek osztályainak hierarchiája

Ezek a szervertípusok a kéréseket szinkronizáltan teljesítik, azaz minden kérés teljesítését csak akkor kezdik meg, ha az előző kérés végrehajtása már lefutott. Számításigényes, hosszú, nagy adatmennyiséggel dolgozó kérések esetén érdemes őket külön folyamatokba, szálakba szervezni; az asszinkron viselkedés megvalósítására a ForkingMixIn és ThreadingMixIn osztályok szolgálnak. Olyan rendszerkörnyezet esetén, ahol a folyamatok és szálak létrehozása és kezelése költséges művelet, a select() metódus használható: ez a művelet a beérkező kérések közül választ egyet (vagy a soronkövetkezőt, vagy egy éppen bejövőt), majd annak végrehajtását kezdeményezni.

Egy szerver megvalósítását egy kéréskiszolgáló (request handler) definiálásával kell kezdeni, melyet a BaseRequestHandler osztályból való származtatással tehetünk meg. Az osztály handle() metódusának felüldefiniálásával egyéni módon kezelhetjük a bejövő kéréseket. A választott szervertípusunk példányosításakor meghatározzuk a szerver címét (host, port) és a request handler típusát. A kérések teljesítésének módjának különbőzőképpen kell zajlania TCP és UDP kapcsolatok esetén, ennek áthidalására a StreamRequestHandler és a DatagramRequestHandler osztályok nyújtanak megoldást.

Request handlerek osztályainak hierarchiája

Szerverobjektumok műveletei

server_activate()
A szerver konstruktora által hívódik meg, megindul a listen() a socketen

server_bind()
A szerver konstruktora által hívódik meg, a socketet a megfelelő címre állítja

fileno()
Visszaadja a socket leírót (egész értékű), amelyen a szerver figyel

handle_request()
Teljesít egy kérést az alábbi lépések végrehajtásával:

    get_request()
    Kérés fogadása

    verify_request(request, client_address)
    Visszatérési értéke true, ha a kérés végrehajtásra kerül, false ha megtagadjuk

    process_request(request, client_address)
    A végrehajtás elindítása, majd finish_request() kérés hívása, mely példányosítja a
    definiált request handler osztály objektumát, és meghívja annak handle() metódusát

serve_forever(poll_interval=0.5)
A shutdown() hívás erejéig teljesíti a kéréseket; minden megadott másodpercben ellenőrzi, hogy érkezett-e shutdown() utasítás.

Request handler objektumok műveletei

setup()
A handle() eljárás előtt hívódik meg, inicializációs feladatokat hajt végre.

handle()
A kérések kiszolgálását megvalósító művelet.

finish()
A handle() metódus lefutása után hívott eljárás, mellyel utófeladatokat végezhetünk az objektumon.

A legtöbb művelet alapértelmezett implementációja üres; az egyes eljárások felüldefiniálásával egyéni működést definiálhatunk a szerver számára.

Egyszerű TCP szerver példa

import socketserver class CustomTCPHandler(socketserver.BaseRequestHandler): # a szerver request handler-e def handle(self): self.data = self.request.recv(1024).strip() print("%s wrote:" % self.client_address[0]) print(self.data) self.request.send(self.data) # visszakuldjuk a kapott uzenetet if __name__ == "__main__": HOST, PORT = "localhost", 9999 server = socketserver.TCPServer((HOST, PORT), CustomTCPHandler) server.serve_forever() # shutdown()-ig kiszolgalunk

A http.server modul

Python3-ban az ezelőtt különálló modult alkotó BaseHTTPServer-t beleolvasztották a http.server modulba, mely két fontos osztályt is tartalmaz webszerverek megvalósítására (SimpleHTTPServer és CGIHTTPServer).

A HTTPServer osztály a socketserver.TCPServer osztály leszármazottja, tehát implementálja a BaseServer interfészt. Az osztály példányosításakor (HTTPServer(server_address, RequestHandlerClass)¶) a szerver címét várja, melyet a server_name és server_port példányváltozók tárolnak a program futása során. A szerverobjektumot a request handler-ből is elérjük annak server példányváltozóján keresztül.

A BaseHTTPRequestHandler osztály leszármazottjai a szerverhez beérkező kérések kiszolgálásáért felelnek; értelmezik a kérést, majd végrehajtják a kérés típusának megfelelő eljárást.

Egyszerű HTTP szerver példa

import http.server def run_while_true(server_class=http.server.HTTPServer, handler_class=http.server.BaseHTTPRequestHandler): server_address = ('', 8000) httpd = server_class(server_address, handler_class) while keep_running(): httpd.handle_request()

A http.client modul

A Python3 előtt httplib néven szereplő modul HTTP és HTTPS protokollok kliens oldali használatára alkalmas osztályokat tartalmaz.

Osztályok

HTTPConnection(host[, port[, strict[, timeout[, source_address]]]])
Egy HTTPConnection objektum egy HTTP szerverrel lebonyolított tranzakciót reprezentál. Példányosítása egy hostnév és további opcionális paraméterek átadásával történik: portszám (alapértelmezett: 80), true/false érték attól függően, meg kívánjuk-e jeleníteni a BadStatusLine hibaüzeneteket, timeout másodpercekben, valamint a forrás címe host-port pár formájában.

HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address]]]]]])
A HTTPConnection osztály leszármazottja SSL alapú kommunikáció használatára. Az opcionális key_file paraméter privát kulcsot, a cert_file pedig tanusítványt vár.

HTTPResponse(sock[, debuglevel=0][, strict=0])
Példányai a sikeres kapcsolatfelvétel során térnek vissza – felhasználó nem hozhat létre példányokat.

HTTPMessage
HTTP üzenetek hordozója, melyet a felhasználó közvetlenül nem példányosíthat.

Kivételek

HTTPException
A modulban található összes kivétel őse, az Exception osztály leszármazottja.

NotConnected
A kapcsolat nem jött létre

InvalidUrl
A port nem numerikus értéket hordoz vagy üres.

BadStatusLine
A szerver visszaadott státuszkódja ismeretlen értéket hordoz.

Konstansok

HTTP_PORT
A http protokoll alapértelmezett portja (80)

HTTPS_PORT
A https protokoll alapértelmezett portja (443)

Néhány fontosabb státuszkód

PROCESSING102
OK200
CREATED201
ACCEPTED202
FOUND302
TEMPORARY_REDIRECT307
UNAUTHORIZED401
FORBIDDEN403
NOT_FOUND404
REQUEST_TIMEOUT408
BAD_GATEWAY502
SERVICE_UNAVAILABLE503