Įvaldykite Python asyncio žemo lygio tinklų kūrimą. Šis gilus panirimas apima Transportus ir Protokolus, su pavyzdžiais didelio našumo tinklo programoms kurti.
Iššifruojant Python Asyncio transportą: nuodugnus panirimas į žemo lygio tinklų kūrimą
Šiuolaikiniame Python pasaulyje, asyncio
tapo didelio našumo tinklų programavimo kertiniu akmeniu. Kūrėjai dažnai pradeda nuo jo puikių aukšto lygio API, naudodami async
ir await
su tokiomis bibliotekomis kaip aiohttp
ar FastAPI
, kad sukurtų jautrias programas su nepaprastu lengvumu. StreamReader
ir StreamWriter
objektai, kuriuos teikia tokios funkcijos kaip asyncio.open_connection()
, siūlo nuostabiai paprastą, nuoseklų būdą tvarkyti tinklo įvestį/išvestį. Bet kas nutinka, kai abstrakcijos nepakanka? Ką daryti, jei reikia įgyvendinti sudėtingą, būseną palaikantį arba nestandartinį tinklo protokolą? Ką daryti, jei norite išspausti paskutinį našumo lašą, tiesiogiai kontroliuodami pagrindinį ryšį? Būtent čia slypi tikrasis asyncio tinklo galimybių pagrindas: žemo lygio Transporto ir Protokolo API. Nors iš pradžių tai gali atrodyti bauginančiai, šio galingo dueto supratimas atveria naują valdymo ir lankstumo lygį, leidžiantį sukurti praktiškai bet kokią įsivaizduojamą tinklo programą. Šis išsamus vadovas atvers abstrakcijos sluoksnius, ištyrins simbiotinį ryšį tarp Transportų ir Protokolų ir pateiks praktinius pavyzdžius, kad galėtumėte įvaldyti žemo lygio asinchroninį tinklų kūrimą Python kalba.
Du Asyncio tinklų kūrimo veidai: aukšto lygio ir žemo lygio
Prieš gilindamiesi į žemo lygio API, labai svarbu suprasti jų vietą asyncio ekosistemoje. Asyncio sumaniai pateikia du skirtingus tinklo komunikacijos sluoksnius, kurių kiekvienas pritaikytas skirtingiems naudojimo atvejams.
Aukšto lygio API: srautai (Streams)
Aukšto lygio API, dažnai vadinama "Srautais" (Streams), yra tai, ką dauguma kūrėjų pamato pirmiausia. Kai naudojate asyncio.open_connection()
arba asyncio.start_server()
, gaunate StreamReader
ir StreamWriter
objektus. Ši API sukurta siekiant paprastumo ir naudojimo patogumo.
- Imperatyvus stilius: Jis leidžia rašyti kodą, kuris atrodo nuoseklus. Jūs
await reader.read(100)
, kad gautumėte 100 baitų, tadawriter.write(data)
, kad išsiųstumėte atsakymą. Šisasync/await
modelis yra intuityvus ir lengvai suprantamas. - Patogūs pagalbininkai: Jis teikia metodus, tokius kaip
readuntil(separator)
irreadexactly(n)
, kurie atlieka įprastas rėminimo užduotis, išlaisvindami jus nuo buferių valdymo rankiniu būdu. - Idealūs naudojimo atvejai: Puikiai tinka paprastiems užklausos-atsakymo protokolams (pvz., paprastam HTTP klientui), eilutėmis pagrįstiems protokolams (pvz., Redis ar SMTP) arba bet kuriai situacijai, kai komunikacija vyksta numatomu, linijiniu srautu.
Tačiau šis paprastumas turi ir trūkumų. Srautais pagrįstas metodas gali būti mažiau efektyvus didelio lygiagretumo, įvykiais pagrįstiems protokolams, kur nepageidaujami pranešimai gali atsirasti bet kuriuo metu. Nuoseklus await
modelis gali apsunkinti vienu metu vykstančių skaitymų ir rašymų valdymą arba sudėtingų ryšio būsenų tvarkymą.
Žemo lygio API: transportai ir protokolai
Tai yra pagrindinis sluoksnis, ant kurio iš tikrųjų pastatyta aukšto lygio Srautų API. Žemo lygio API naudoja dizaino modelį, pagrįstą dviem atskirais komponentais: transportais ir protokolais.
- Įvykiais pagrįstas stilius: Užuot jūs skambinę funkcijai, kad gautumėte duomenis, asyncio iškviečia jūsų objekto metodus, kai įvyksta įvykiai (pvz., užmegztas ryšys, gauti duomenys). Tai yra grįžtamojo iškvietimo (callback) pagrindu veikiantis metodas.
- Atskirų sričių atskyrimas: Jis aiškiai atskiria "ką" nuo "kaip". Protokolas apibrėžia, ką daryti su duomenimis (jūsų programos logika), o Transportas valdo, kaip duomenys siunčiami ir gaunami per tinklą (įvesties/išvesties mechanizmas).
- Maksimalus valdymas: Ši API suteikia jums smulkų valdymą buferizavimo, srauto valdymo (atbulinio slėgio) ir ryšio gyvavimo ciklo atžvilgiu.
- Idealūs naudojimo atvejai: Būtinas įgyvendinant pasirinktinius dvejetainius ar tekstinius protokolus, kuriant didelio našumo serverius, kurie valdo tūkstančius nuolatinių ryšių, arba kuriant tinklo sistemas ir bibliotekas.
Pagalvokite taip: Srautų API yra tarsi maisto rinkinio užsakymas. Jūs gaunate iš anksto porcijomis suskirstytus ingredientus ir paprastą receptą. Transporto ir Protokolo API yra tarsi buvimas virėju profesionalioje virtuvėje su žaliais ingredientais ir visiška kontrole kiekviename proceso žingsnyje. Abu gali pagaminti puikų patiekalą, tačiau pastarasis siūlo neribotą kūrybiškumą ir valdymą.
Pagrindiniai komponentai: išsamesnis žvilgsnis į transportus ir protokolus
Žemo lygio API galia slypi elegantiškame protokolo ir transporto sąveikoje. Jie yra skirtingi, bet neatsiejami partneriai bet kurioje žemo lygio asyncio tinklo programoje.
Protokolas: Jūsų programos smegenys
Protokolas yra klasė, kurią rašote jūs. Ji paveldima iš asyncio.Protocol
(arba vieno iš jo variantų) ir apima būseną bei logiką vienam tinklo ryšiui tvarkyti. Jūs patys nekuriate šios klasės egzemplioriaus; jūs ją pateikiate asyncio (pvz., į loop.create_server
), o asyncio sukuria naują jūsų protokolo egzempliorių kiekvienam naujam kliento ryšiui.
Jūsų protokolo klasę apibrėžia įvykių tvarkyklių metodų rinkinys, kuriuos įvykių ciklas iškviečia skirtingais ryšio gyvavimo ciklo momentais. Svarbiausi iš jų yra:
connection_made(self, transport)
Iškviečiamas lygiai vieną kartą, kai sėkmingai užmezgamas naujas ryšys. Tai yra jūsų įėjimo taškas. Būtent čia gaunate transport
objektą, kuris reprezentuoja ryšį. Visada turėtumėte išsaugoti nuorodą į jį, paprastai kaip self.transport
. Tai ideali vieta atlikti bet kokį inicijavimą ryšiui, pavyzdžiui, nustatyti buferius arba registruoti kolegos adresą.
data_received(self, data)
Jūsų protokolo širdis. Šis metodas iškviečiamas kaskart, kai gaunami nauji duomenys iš kito ryšio galo. Argumentas data
yra bytes
objektas. Labai svarbu atsiminti, kad TCP yra srautinis protokolas, o ne pranešimų protokolas. Vienas loginis pranešimas iš jūsų programos gali būti padalintas į kelis data_received
iškvietimus, arba keli maži pranešimai gali būti sujungti į vieną iškvietimą. Jūsų kodas privalo tvarkyti šį buferizavimą ir analizavimą.
connection_lost(self, exc)
Iškviečiamas, kai ryšys nutraukiamas. Tai gali nutikti dėl kelių priežasčių. Jei ryšys nutraukiamas švariai (pvz., kita pusė jį nutraukia, arba jūs iškviečiate transport.close()
), exc
bus None
. Jei ryšys nutraukiamas dėl klaidos (pvz., tinklo gedimo, atstatymo), exc
bus išimties objektas, detalizuojantis klaidą. Tai yra jūsų galimybė atlikti valymą, užfiksuoti atsijungimą arba bandyti prisijungti iš naujo, jei kuriate klientą.
eof_received(self)
Tai subtilesnis grįžtamasis iškvietimas. Jis iškviečiamas, kai kitas galas signalizuoja, kad daugiau duomenų nesiųs (pvz., iškviesdamas shutdown(SHUT_WR)
POSIX sistemoje), bet ryšys gali būti vis dar atviras, kad galėtumėte siųsti duomenis. Jei iš šio metodo grąžinsite True
, transportas bus uždarytas. Jei grąžinsite False
(numatytasis), būsite atsakingi už transporto uždarymą vėliau patys.
Transportas: ryšio kanalas
Transportas yra objektas, kurį teikia asyncio. Jūs jo nekuriate; jį gaunate savo protokolo connection_made
metode. Jis veikia kaip aukšto lygio abstrakcija virš pagrindinio tinklo soketo ir įvykių ciklo įvesties/išvesties planavimo. Jo pagrindinė užduotis yra tvarkyti duomenų siuntimą ir ryšio valdymą.
Su transportu sąveikaujate per jo metodus:
transport.write(data)
Pagrindinis duomenų siuntimo metodas. data
turi būti bytes
objektas. Šis metodas neveikia blokuojančiai. Jis nesiunčia duomenų iškart. Vietoj to, jis patalpina duomenis į vidinį rašymo buferį, o įvykių ciklas siunčia juos per tinklą kuo efektyviau fone.
transport.writelines(list_of_data)
Efektyvesnis būdas vienu metu į buferį įrašyti bytes
objektų seką, galbūt sumažinant sistemos iškvietimų skaičių.
transport.close()
Tai inicijuoja sklandų išjungimą. Transportas pirmiausia išvalys visus likusius duomenis savo rašymo buferyje ir tada nutrauks ryšį. Po close()
iškvietimo daugiau duomenų negalima rašyti.
transport.abort()
Tai atlieka priverstinį išjungimą. Ryšys iškart nutraukiamas, o visi laukiantys duomenys rašymo buferyje išmetami. Tai turėtų būti naudojama išskirtinėmis aplinkybėmis.
transport.get_extra_info(name, default=None)
Labai naudingas metodas savitikrai. Galite gauti informacijos apie ryšį, pvz., kolegos adresą ('peername'
), pagrindinį soketo objektą ('socket'
) arba SSL/TLS sertifikato informaciją ('ssl_object'
).
Simbiotinis ryšys
Šio dizaino grožis slypi aiškiame, cikliniame informacijos sraute:
- Nustatymas: Įvykių ciklas priima naują ryšį.
- Inicijavimas: Ciklas sukuria jūsų
Protocol
klasės egzempliorių irTransport
objektą, atstovaujantį ryšiui. - Susiejimas: Ciklas iškviečia
your_protocol.connection_made(transport)
, sujungdamas du objektus. Jūsų protokolas dabar turi būdą siųsti duomenis. - Duomenų priėmimas: Kai duomenys pasiekia tinklo soketą, įvykių ciklas atsibunda, nuskaito duomenis ir iškviečia
your_protocol.data_received(data)
. - Apdirbimas: Jūsų protokolo logika apdoroja gautus duomenis.
- Duomenų siuntimas: Pagal savo logiką, jūsų protokolas iškviečia
self.transport.write(response_data)
, kad išsiųstų atsakymą. Duomenys buferizuojami. - Fono I/O: Įvykių ciklas tvarko neblokuojantį buferizuotų duomenų siuntimą per transportą.
- Nutraukimas: Kai ryšys baigiasi, įvykių ciklas iškviečia
your_protocol.connection_lost(exc)
galutiniam valymui.
Praktinio pavyzdžio kūrimas: aido serveris ir klientas
Teorija yra puiku, tačiau geriausias būdas suprasti transportus ir protokolus yra ką nors sukurti. Sukurkime klasikinį aido serverį ir atitinkamą klientą. Serveris priims ryšius ir tiesiog išsiųs atgal visus gautus duomenis.
Aido serverio implementacija
Pirmiausia apibrėšime savo serverio protokolo pusę. Tai nepaprastai paprasta, demonstruojanti pagrindinius įvykių tvarkykles.
import asyncio
class EchoServerProtocol(asyncio.Protocol):
def connection_made(self, transport):
# Užmegztas naujas ryšys.
# Gaukite nuotolinį adresą registravimui.
peername = transport.get_extra_info('peername')
print(f"Ryšys iš: {peername}")
# Išsaugokite transportą vėlesniam naudojimui.
self.transport = transport
def data_received(self, data):
# Gauti duomenys iš kliento.
message = data.decode()
print(f"Gauti duomenys: {message.strip()}")
# Grąžinkite duomenis klientui.
print(f"Aidas grąžinamas: {message.strip()}")
self.transport.write(data)
def connection_lost(self, exc):
# Ryšys buvo nutrauktas.
print("Ryšys nutrauktas.")
# Transportas uždaromas automatiškai, nereikia kviesti self.transport.close() čia.
async def main_server():
# Gaukite įvykių ciklo nuorodą, nes planuojame vykdyti serverį neribotą laiką.
loop = asyncio.get_running_loop()
host = '127.0.0.1'
port = 8888
# The `create_server` korutina sukuria ir paleidžia serverį.
# Pirmasis argumentas yra protocol_factory, iškviečiamas objektas, kuris grąžina naują protokolo egzempliorių.
# Mūsų atveju, tiesiog perduodant klasę `EchoServerProtocol` veikia.
server = await loop.create_server(
lambda: EchoServerProtocol(),
host,
port)
addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
print(f'Veikia {addrs}')
# Serveris veikia fone. Kad pagrindinė korutina išliktų gyva,
# galime laukti kažko, kas niekada nebaigiama, pavyzdžiui, naujo Future.
# Šiam pavyzdžiui, tiesiog vykdysime jį "amžinai".
async with server:
await server.serve_forever()
if __name__ == "__main__":
try:
# Norėdami paleisti serverį:
asyncio.run(main_server())
except KeyboardInterrupt:
print("Serveris išjungtas.")
Šiame serverio kode loop.create_server()
yra esminis. Jis susieja su nurodytu pagrindiniu kompiuteriu ir prievadu bei nurodo įvykių ciklui pradėti klausytis naujų ryšių. Kiekvienam ateinančiam ryšiui jis iškviečia mūsų protocol_factory
(funkciją lambda: EchoServerProtocol()
), kad sukurtų naują protokolo egzempliorių, skirtą tam konkrečiam klientui.
Aido kliento implementacija
Kliento protokolas yra šiek tiek sudėtingesnis, nes jam reikia valdyti savo būseną: kokį pranešimą siųsti ir kada jis laiko savo darbą "baigtu". Dažnas modelis yra naudoti asyncio.Future
arba asyncio.Event
, kad būtų signalizuojama apie užbaigimą pagrindinei korutinai, kuri paleido klientą.
import asyncio
class EchoClientProtocol(asyncio.Protocol):
def __init__(self, message, on_con_lost):
self.message = message
self.on_con_lost = on_con_lost
self.transport = None
def connection_made(self, transport):
self.transport = transport
print(f"Siunčiama: {self.message}")
self.transport.write(self.message.encode())
def data_received(self, data):
print(f"Gautas aidas: {data.decode().strip()}")
def connection_lost(self, exc):
print("Serveris nutraukė ryšį")
# Signalizuokite, kad ryšys nutrauktas ir užduotis baigta.
self.on_con_lost.set_result(True)
def eof_received(self):
# Tai gali būti iškviesta, jei serveris siunčia EOF prieš uždarydamas ryšį.
print("Gautas EOF iš serverio.")
async def main_client():
loop = asyncio.get_running_loop()
# The on_con_lost future is used to signal the completion of the client's work.
on_con_lost = loop.create_future()
message = "Hello World!"
host = '127.0.0.1'
port = 8888
# `create_connection` užmezga ryšį ir susieja protokolą.
try:
transport, protocol = await loop.create_connection(
lambda: EchoClientProtocol(message, on_con_lost),
host,
port)
except ConnectionRefusedError:
print("Ryšys atmestas. Ar serveris veikia?")
return
# Laukite, kol protokolas signalizuos, kad ryšys nutrauktas.
try:
await on_con_lost
finally:
# Švariai uždarykite transportą.
transport.close()
if __name__ == "__main__":
# Norėdami paleisti klientą:
# Pirmiausia paleiskite serverį viename terminale.
# Tada paleiskite šį scenarijų kitame terminale.
asyncio.run(main_client())
Čia loop.create_connection()
yra kliento pusės atitikmuo create_server
. Jis bando prisijungti prie nurodyto adreso. Jei sėkmingai prisijungia, jis sukuria mūsų EchoClientProtocol
egzempliorių ir iškviečia jo connection_made
metodą. on_con_lost
Future naudojimas yra kritinis modelis. main_client
korutina await
šios ateities, efektyviai sustabdydama savo vykdymą, kol protokolas signalizuos, kad jo darbas baigtas, iškviesdamas on_con_lost.set_result(True)
iš connection_lost
.
Pažangios koncepcijos ir realaus pasaulio scenarijai
Aido pavyzdys apima pagrindus, tačiau realaus pasaulio protokolai retai būna tokie paprasti. Panagrinėkime keletą pažangesnių temų, su kuriomis neišvengiamai susidursite.
Žinučių įrėminimo ir buferizavimo tvarkymas
Svarbiausia koncepcija, kurią reikia suprasti po pagrindų, yra tai, kad TCP yra baitų srautas. Nėra jokių įgimtų "žinučių" ribų. Jei klientas siunčia "Hello", o tada "World", jūsų serverio data_received
gali būti iškviestas vieną kartą su b'HelloWorld'
, du kartus su b'Hello'
ir b'World'
, arba net kelis kartus su daliniais duomenimis.
Jūsų protokolas yra atsakingas už "įrėminimą" — šių baitų srautų surinkimą į prasmingas žinutes. Dažna strategija yra naudoti skyriklį, pvz., naujos eilutės simbolį (\n
).
Štai pakeistas protokolas, kuris buferizuoja duomenis, kol randa naują eilutę, apdorodamas po vieną eilutę vienu metu.
class LineBasedProtocol(asyncio.Protocol):
def __init__(self):
self._buffer = b''
self.transport = None
def connection_made(self, transport):
self.transport = transport
print("Ryšys užmegztas.")
def data_received(self, data):
# Pridėkite naujus duomenis prie vidinio buferio
self._buffer += data
# Apdorokite tiek pilnų eilučių, kiek turime buferyje
while b'\n' in self._buffer:
line, self._buffer = self._buffer.split(b'\n', 1)
self.process_line(line.decode().strip())
def process_line(self, line):
# Čia eina jūsų programos logika vienai žinutei
print(f"Apdorojama visa žinutė: {line}")
response = f"Apdorota: {line}\n"
self.transport.write(response.encode())
def connection_lost(self, exc):
print("Ryšys nutrauktas.")
Srauto valdymo (atbulinio slėgio) valdymas
Kas nutinka, jei jūsų programa rašo duomenis į transportą greičiau, nei tinklas ar nuotolinis partneris gali juos apdoroti? Duomenys kaupiasi transporto vidiniame buferyje. Jei tai tęsiasi nekontroliuojamai, buferis gali augti neribotai, sunaudodamas visą galimą atmintį. Ši problema yra žinoma kaip "atbulinio slėgio" trūkumas.
Asyncio suteikia mechanizmą, kaip tai tvarkyti. Transportas stebi savo buferio dydį. Kai buferis viršija tam tikrą aukštą ribą, įvykių ciklas iškviečia jūsų protokolo metodą pause_writing()
. Tai yra signalas jūsų programai sustabdyti duomenų siuntimą. Kai buferis nusausinamas žemiau žemos ribos, ciklas iškviečia resume_writing()
, signalizuodamas, kad vėl saugu siųsti duomenis.
class FlowControlledProtocol(asyncio.Protocol):
def __init__(self):
self._paused = False
self._data_source = some_data_generator() # Įsivaizduokite duomenų šaltinį
self.transport = None
def connection_made(self, transport):
self.transport = transport
self.resume_writing() # Pradėkite rašymo procesą
def pause_writing(self):
# Transporto buferis pilnas.
print("Rašymas pristabdytas.")
self._paused = True
def resume_writing(self):
# Transporto buferis išvalytas.
print("Rašymas atnaujintas.")
self._paused = False
self._write_more_data()
def _write_more_data(self):
# Tai yra mūsų programos rašymo ciklas.
while not self._paused:
try:
data = next(self._data_source)
self.transport.write(data)
except StopIteration:
self.transport.close()
break # Nėra daugiau duomenų siuntimui
# Patikrinkite buferio dydį, kad pamatytumėte, ar turėtume nedelsiant pristabdyti
if self.transport.get_write_buffer_size() > 0:
self.pause_writing()
Be TCP: kiti transportai
Nors TCP yra dažniausiai naudojamas atvejis, Transporto/Protokolo modelis juo neapsiriboja. Asyncio teikia abstrakcijas kitų tipų ryšiams:
- UDP: Ryšiams be jungties naudojate
loop.create_datagram_endpoint()
. Tai suteikia jumsDatagramTransport
ir jūs įgyvendinsiteasyncio.DatagramProtocol
su tokiais metodais kaipdatagram_received(data, addr)
irerror_received(exc)
. - SSL/TLS: Šifravimo pridėjimas yra nepaprastai paprastas. Jūs perduodate
ssl.SSLContext
objektą įloop.create_server()
arbaloop.create_connection()
. Asyncio automatiškai tvarko TLS rankos paspaudimą, ir jūs gaunate saugų transportą. Jūsų protokolo kodo visai nereikia keisti. - Antriniai procesai: Ryšiams su antriniais procesais per jų standartinius įvesties/išvesties vamzdžius,
loop.subprocess_exec()
irloop.subprocess_shell()
gali būti naudojami suasyncio.SubprocessProtocol
. Tai leidžia jums valdyti antrinius procesus visiškai asinchroniniu, neblokuojančiu būdu.
Strateginis sprendimas: kada naudoti transportus, o kada srautus
Turint dvi galingas API, pagrindinis architektūrinis sprendimas yra pasirinkti tinkamą užduočiai. Štai vadovas, padėsiantis jums apsispręsti.
Pasirinkite srautus (StreamReader
/StreamWriter
), kai...
- Jūsų protokolas yra paprastas ir pagrįstas užklausa-atsakymu. Jei logika yra "skaityti užklausą, ją apdoroti, rašyti atsakymą", srautai yra tobuli.
- Kuriate klientą žinomam, eilutėmis pagrįstam arba fiksuoto ilgio pranešimų protokolui. Pavyzdžiui, bendraujate su Redis serveriu arba paprastu FTP serveriu.
- Prioritetą teikiate kodo skaitomumui ir linijiniam, imperatyviam stiliui.
async/await
sintaksę su srautais dažnai lengviau suprasti kūrėjams, naujiems asinchroniniame programavime. - Greitas prototipų kūrimas yra esminis. Galite sukurti paprastą klientą ar serverį, veikiantį su srautais, vos per kelias kodo eilutes.
Pasirinkite transportus ir protokolus, kai...
- Įgyvendinate sudėtingą arba pasirinktinį tinklo protokolą nuo nulio. Tai yra pagrindinis naudojimo atvejis. Pagalvokite apie protokolus žaidimams, finansinių duomenų srautams, IoT įrenginiams ar lygiaverčių tinklų programoms.
- Jūsų protokolas yra labai įvykiais pagrįstas ir ne tik užklausa-atsakymas. Jei serveris bet kuriuo metu gali siųsti nepageidaujamus pranešimus klientui, grįžtamaisiais iškvietimais pagrįstas protokolų pobūdis yra natūralesnis.
- Jums reikia maksimalaus našumo ir minimalios papildomos apkrovos. Protokolai suteikia jums tiesesnį kelią į įvykių ciklą, aplenkdami tam tikrą papildomą apkrovą, susijusią su Srautų API.
- Reikalaujate smulkaus ryšio valdymo. Tai apima rankinį buferio valdymą, aiškų srauto valdymą (
pause/resume_writing
) ir detalų ryšio gyvavimo ciklo tvarkymą. - Kuriate tinklo sistemą ar biblioteką. Jei teikiate įrankį kitiems kūrėjams, tvirtas ir lankstus Protokolo/Transporto API pobūdis dažnai yra tinkamiausias pagrindas.
Išvada: Asyncio pagrindų priėmimas
Python asyncio
biblioteka yra sluoksninės architektūros šedevras. Nors aukšto lygio Srautų API suteikia prieinamą ir produktyvų įėjimo tašką, būtent žemo lygio Transporto ir Protokolo API atspindi tikrąjį, galingą asyncio tinklo galimybių pagrindą. Atskyrus įvesties/išvesties mechanizmą (Transportą) nuo programos logikos (Protokolo), ji suteikia tvirtą, keičiamo dydžio ir nepaprastai lankstų modelį sudėtingoms tinklo programoms kurti.
Šios žemo lygio abstrakcijos supratimas yra ne tik akademinis pratimas; tai praktinis įgūdis, kuris suteikia jums galimybę peržengti paprastų klientų ir serverių ribas. Tai suteikia jums pasitikėjimo sprendžiant bet kokį tinklo protokolą, galimybę optimizuoti našumą esant slėgiui ir gebėjimą kurti naujos kartos didelio našumo, asinchronines paslaugas Python kalba. Kitą kartą susidūrę su sudėtinga tinklų problema, prisiminkite galią, slypinčią po paviršiumi, ir nedvejodami pasinaudokite elegantišku Transportų ir Protokolų duetu.