12.7. Funcții de retroapelare ale canalului¶
Obiectul backend transmis către protocol.register() este o clasă Python. Biblioteca de protocol nu întreabă clasa ce metode implementează; ea inspectează instanța și conectează metodele pe care le găsește. Această introspecție este cea care face ca interfața backend să fie flexibilă: cel mai mic backend util are două metode, cel mai elaborat are douăsprezece, iar aplicația optează pentru fiecare capabilitate, câte o metodă pe rând.
12.7.1. Regulile de introspecție¶
Când rulează protocol.register(), biblioteca parcurge o listă fixă de nume apelabile și leagă fiecare nume pe care îl găsește în instanța backend:
Adăugarea metodei
readla clasă activeazăCHANNEL_FLAG_READ. Un apel al gazdei cătrechannel_read()ajunge la backend doar dacă acest indicator este setat.Adăugarea metodei
writeactiveazăCHANNEL_FLAG_WRITE, permițândchannel_write().Adăugarea metodelor
lockșiunlockactiveazăCHANNEL_FLAG_LOCK, permițând gazdei să blocheze canalul pentru o citire atomică pe mai multe pachete.Adăugarea metodei
pollpermite gazdei să întrebe ieftin „este ceva gata?”, fără a forța o citire completă.
Metodele lipsă nu sunt erori – biblioteca de protocol lasă pur și simplu capabilitatea corespunzătoare dezactivată. Un backend cu doar size și read este perfect valid; este un canal de date doar pentru citire.
12.7.2. Un canal de senzor doar pentru citire¶
Un canal de senzor care publică o citire proaspătă de fiecare dată când gazda cere și refuză scrierile gazdei utilizează patru dintre funcțiile de retroapelare:
import protocol
import struct
class TempChannel:
def __init__(self, read_sensor):
self._read_sensor = read_sensor
self._buf = b''
self._fresh = False
def poll(self):
# Tell the host whether a reading is waiting.
return self._fresh
def size(self):
# Sample fresh data on every host-side size query.
value = self._read_sensor()
self._buf = struct.pack('<f', value)
self._fresh = True
return len(self._buf)
def read(self, offset, size):
end = offset + size
if end >= len(self._buf):
self._fresh = False
return self._buf[offset:end]
protocol.register(name='temp', backend=TempChannel(read_temperature))
Parcurgând ce face fiecare metodă:
pollreturnează indicatorul de prospețime. Gazda îl apelează înainte de citire și omite citirea complet atunci când returneazăFalse. Acest lucru economisește costul dus-întors pentru „încă nu există date noi.”sizeregenerează tamponul (buffer) la cerere și raportează lungimea acestuia. Efectuarea eșantionării aici înseamnă că backendul nu are nevoie de o sarcină de fundal – un apel al gazdei declanșează fiecare măsurătoare.readreturnează o secțiune din tampon (buffer). Biblioteca de protocol îl poate apela de mai multe ori atunci când tamponul este mai mare decât sarcina utilă maximă negociată; argumentuloffsetparcurge fragmentele.Absența metodei
writeînseamnă că scrierile gazdei sunt refuzate la nivelul de încadrare, înainte ca backendul să fie implicat.
12.7.3. Setul complet de funcții de retroapelare¶
Pentru referință, fiecare metodă pe care biblioteca o caută într-un backend:
Metodă |
Returnează |
Scop |
|---|---|---|
|
object |
Inițializare opțională unică atunci când canalul se leagă pentru prima dată de o gazdă. Returnează orice valoare diferită de |
|
bool |
Returnează |
|
bool |
Achiziționează canalul pentru un transfer atomic pe mai multe pachete. |
|
bool |
Eliberează un |
|
int |
Numărul de octeți care pot fi citiți în prezent din canal. |
|
tuple |
Până la patru numere întregi care descriu structura datelor (de exemplu, înălțimea imaginii, lățimea, numărul de octeți). Folosit de gazdă pentru a despacheta tampoane tipizate. |
|
bytes |
Returnează până la size octeți începând de la offset. Apelat o dată per fragment atunci când sarcina utilă depășește maximul negociat. |
|
bytes |
Variantă fără copiere a metodei |
|
int |
Gazda a scris data la offset. |
|
int |
Cod de operație definit de aplicație, în afara modelului de citire/scriere. O valoare returnată negativă este o eroare. |
|
object |
Eliberează orice date stocate în tampon (buffer). Apelat atunci când gazda dorește să reseteze canalul. |
|
bool |
Semnificativ doar pe backenduri care reprezintă un transport fizic (canalele USB încorporate). Canalele de aplicație nu au nevoie de acest lucru. |
Aceasta este întreaga interfață backend. Douăsprezece nume de metode, toate opționale, iar biblioteca de protocol decide ce poate face fiecare canal pe baza celor care sunt prezente.