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.