12.7. פונקציות callback של ערוצים¶
אובייקט ה-backend המועבר אל protocol.register() הוא מחלקת Python. ספריית הפרוטוקול אינה שואלת את המחלקה אילו מתודות היא ממשת; היא בוחנת את המופע ומחברת את אלו שהיא מוצאת. אינטרוספקציה זו היא מה שמקנה לממשק ה-backend את גמישותו: ה-backend השימושי הקטן ביותר מורכב משתי מתודות, המורכב ביותר משתים-עשרה, והאפליקציה מצטרפת לכל יכולת בנפרד, מתודה אחת בכל פעם.
12.7.1. כללי האינטרוספקציה¶
כאשר protocol.register() רץ, הספרייה עוברת על רשימה קבועה של שמות הניתנים לקריאה ומקשרת כל אחד שהיא מוצאת על מופע ה-backend:
הוספת
readלמחלקה מדליקה אתCHANNEL_FLAG_READ. קריאה מהמארח אלchannel_read()מגיעה אל ה-backend רק אם דגל זה מוגדר.הוספת
writeמדליקה אתCHANNEL_FLAG_WRITE, ומאפשרת אתchannel_write().הוספת
lockו-unlockמדליקה אתCHANNEL_FLAG_LOCK, ומאפשרת למארח לנעול את הערוץ לצורך קריאה אטומית מרובת מנות (packets).הוספת
pollמאפשרת למארח לשאול ”האם משהו מוכן?“ בזול, בלי לכפות קריאה מלאה.
מתודות חסרות אינן שגיאות – ספריית הפרוטוקול פשוט משאירה את היכולת המתאימה מושבתת. backend עם size ו-read בלבד הוא תקין לחלוטין; זהו ערוץ נתונים לקריאה בלבד.
12.7.2. ערוץ חיישן לקריאה בלבד¶
ערוץ חיישן המפרסם קריאה טרייה בכל פעם שהמארח מבקש, ומסרב לכתיבות מהמארח, עושה שימוש בארבע מפונקציות ה-callback:
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))
מעבר על מה שכל מתודה עושה:
pollמחזירה את דגל הטריות. המארח קורא לה לפני קריאה ומדלג על הקריאה לחלוטין כאשר היא מחזירהFalse. זה חוסך את עלות ההלוך-ושוב במקרה של ”אין נתונים חדשים עדיין“.sizeמייצרת מחדש את החוצץ (buffer) לפי דרישה ומדווחת על אורכו. ביצוע הדגימה כאן משמעו שה-backend אינו זקוק למשימת רקע – קריאה מהמארח מניעה כל מדידה.readמחזירה פלח של החוצץ (buffer). ספריית הפרוטוקול עשויה לקרוא לה יותר מפעם אחת כאשר החוצץ גדול מהמטען המרבי שסוכם; הארגומנטoffsetעובר דרך הקטעים.היעדר
writeמשמעו שכתיבות מהמארח נדחות בשכבת המסגור (framing), לפני שה-backend מעורב.
12.7.3. ערכת ה-callback המלאה¶
לעיון, כל מתודה שהספרייה מחפשת על backend:
מתודה |
מחזירה |
מטרה |
|---|---|---|
|
object |
אתחול חד-פעמי אופציונלי כאשר הערוץ נקשר לראשונה למארח. החזר כל ערך שאינו |
|
bool |
החזר |
|
bool |
תפוס את הערוץ לצורך העברה אטומית מרובת מנות (packets). |
|
bool |
שחרר |
|
int |
מספר הבייטים הניתנים כעת לקריאה מהערוץ. |
|
tuple |
עד ארבעה מספרים שלמים המתארים את מבנה הנתונים (למשל גובה התמונה, רוחב, מספר בייטים). משמש את המארח כדי לפרוס חוצצים מטופסים. |
|
bytes |
החזר עד size בייטים החל מ-offset. נקרא פעם אחת לכל קטע כאשר המטען חורג מהמרבי שסוכם. |
|
bytes |
וריאנט ללא העתקה (zero-copy) של |
|
int |
המארח כתב data ב-offset. |
|
int |
אופקוד מוגדר-אפליקציה מחוץ למודל הקריאה/כתיבה. ערך החזרה שלילי הוא שגיאה. |
|
object |
השלך כל נתון מאוחסן בחוצץ. נקרא כאשר המארח רוצה לאפס את הערוץ. |
|
bool |
משמעותי רק על backends המייצגים תעבורה (transport) פיזית (ערוצי ה-USB המובנים). ערוצי אפליקציה אינם זקוקים לכך. |
זהו ממשק ה-backend בשלמותו. שנים-עשר שמות מתודות, כולם אופציונליים, וספריית הפרוטוקול מחליטה מה כל ערוץ יכול לעשות על סמך אילו מהם נוכחים.