socket — מודול socket#

מודול זה מספק גישה לממשק socket של BSD.

הבדל מ-CPython

לשם יעילות ועקביות, אובייקטי socket ב-MicroPython מממשים ממשק stream (דמוי קובץ) באופן ישיר. ב-CPython, יש להמיר socket לאובייקט דמוי קובץ באמצעות המתודה makefile(). מתודה זו עדיין נתמכת על ידי MicroPython (אך אינה מבצעת דבר), כך שכאשר תאימות ל-CPython חשובה, הקפידו להשתמש בה.

תבנית/תבניות כתובת socket#

תבנית כתובת ה-socket המקורית של מודול socket היא סוג נתונים אטום המוחזר על ידי הפונקציה getaddrinfo(), שיש להשתמש בה לפענוח כתובת טקסטואלית (כולל כתובות מספריות):

sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# You must use getaddrinfo() even for numeric addresses
sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1]
# Now you can use that address
sock.connect(sockaddr)

שימוש ב-getaddrinfo() הוא הדרך היעילה ביותר (הן מבחינת זיכרון והן מבחינת כוח עיבוד) והניידת ביותר לעבודה עם כתובות.

מודול socket מספק גם דרך תואמת-CPython לציון כתובות באמצעות tuples, כמתואר להלן. ב-OpenMV Cam מודול socket מובנה; ניתן לתת כתובות מספריות ישירות בתבנית ה-tuple, אך שמות מתחם יש לפענח תחילה באמצעות getaddrinfo().

לסיכום:

  • השתמשו תמיד ב-getaddrinfo() כדי לפענח שמות מארחים.

  • כתובות tuple המתוארות להלן יכולות לשמש כקיצור לכתובות מספריות, להאקים מהירים ולשימוש אינטראקטיבי.

תבנית כתובת tuple עבור מודול socket:

  • IPv4: (ipv4_address, port), כאשר ipv4_address היא מחרוזת עם כתובת IPv4 מספרית בכתיב נקודות, למשל "8.8.8.8", ו-port הוא מספר פורט שלם בטווח 1-65535. שמות מתחם אינם מתקבלים כ-ipv4_address; פענחו אותם תחילה באמצעות getaddrinfo().

  • IPv6: (ipv6_address, port, flowinfo, scopeid), כאשר ipv6_address היא מחרוזת עם כתובת IPv6 מספרית בכתיב נקודתיים, למשל "2001:db8::1", ו-port הוא מספר פורט שלם בטווח 1-65535. flowinfo חייב להיות 0. scopeid הוא מזהה ההיקף של הממשק עבור כתובות link-local. שמות מתחם אינם מתקבלים כ-ipv6_address; פענחו אותם תחילה באמצעות getaddrinfo().

פונקציות#

socket.getaddrinfo(host: str, port: int, af: int = 0, type: int = 0, proto: int = 0, flags: int = 0, /) List[Tuple]#

מתרגם את ארגומנט המארח/הפורט לרצף של 5-tuples המכילים את כל הארגומנטים הדרושים ליצירת socket המחובר לאותו שירות. הארגומנטים af, type ו-proto (בעלי אותה משמעות כמו עבור הפונקציה socket) יכולים לשמש לסינון סוגי הכתובות המוחזרות. אם פרמטר אינו מצוין או הוא אפס, ניתן להחזיר את כל צירופי הכתובות (מה שמחייב סינון בצד המשתמש).

רשימת ה-5-tuples המתקבלת היא בעלת המבנה הבא:

(family, type, proto, canonname, sockaddr)

הדוגמה הבאה מראה כיצד להתחבר ל-url נתון:

s = socket.socket()
# This assumes that if "type" is not specified, an address for
# SOCK_STREAM will be returned, which may be not true
s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1])

שימוש מומלץ בפרמטרי הסינון:

s = socket.socket()
# Guaranteed to return an address which can be connect'ed to for
# stream operation.
s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1])

הבדל מ-CPython

CPython מעלה חריגת socket.gaierror (תת-מחלקה של OSError) במקרה של שגיאה בפונקציה זו. ב-MicroPython אין socket.gaierror והיא מעלה OSError ישירות. שימו לב שמספרי השגיאה של getaddrinfo() מהווים מרחב שמות נפרד ועשויים שלא להתאים למספרי השגיאה ממודול errno. כדי להבחין בשגיאות getaddrinfo(), הן מיוצגות על ידי מספרים שליליים, בעוד ששגיאות מערכת סטנדרטיות הן מספרים חיוביים (ניתן לגשת למספרי השגיאה באמצעות המאפיין e.args[0] מאובייקט חריגה). השימוש בערכים שליליים הוא פרט זמני שעשוי להשתנות בעתיד.

socket.inet_ntop(af: int, bin_addr: bytes) str#

ממיר כתובת רשת בינארית bin_addr של משפחת הכתובות הנתונה af לייצוג טקסטואלי:

>>> socket.inet_ntop(socket.AF_INET, b"\x7f\0\0\1")
'127.0.0.1'
socket.inet_pton(af: int, txt_addr: str) bytes#

ממיר כתובת רשת טקסטואלית txt_addr של משפחת הכתובות הנתונה af לייצוג בינארי:

>>> socket.inet_pton(socket.AF_INET, "1.2.3.4")
b'\x01\x02\x03\x04'

קבועים#

socket.AF_INET: int#

משפחת כתובות IPv4.

socket.AF_INET6: int#

משפחת כתובות IPv6.

socket.SOCK_STREAM: int#

סוג socket מסוג Stream (TCP).

socket.SOCK_DGRAM: int#

סוג socket מסוג Datagram (UDP).

socket.SOCK_RAW: int#

סוג socket גולמי (Raw).

socket.IPPROTO_IP: int#

רמת פרוטוקול ה-IP. משמש כארגומנט level ל-setsockopt() יחד עם אפשרויות IP_*.

socket.IPPROTO_TCP: int#

פרוטוקול ה-TCP. אינכם צריכים להעביר זאת ל-socket (סוג ה-socket‏ SOCK_STREAM בוחר אותו אוטומטית); השימוש האמיתי היחיד בו הוא כארגומנט level ל-setsockopt() יחד עם אפשרויות TCP_*.

socket.SOL_SOCKET: int#

רמת אפשרות ה-socket. משמש כארגומנט level ל-setsockopt() יחד עם אפשרויות SO_*.

socket.SO_REUSEADDR: int#

מאפשר ל-socket להיקשר לכתובת/פורט שעדיין נמצאים במצב TIME_WAIT.

socket.SO_BROADCAST: int#

מתיר שליחת datagrams לכתובת שידור (broadcast).

socket.SO_KEEPALIVE: int#

מאפשר שידור תקופתי של בדיקות keep-alive על socket מחובר.

socket.SO_SNDTIMEO: int#

פסק זמן לשליחה, באלפיות שנייה, המועבר כארגומנט value ל-setsockopt().

socket.SO_RCVTIMEO: int#

פסק זמן לקבלה, באלפיות שנייה, המועבר כארגומנט value ל-setsockopt().

socket.IP_ADD_MEMBERSHIP: int#

הצטרפות לקבוצת multicast. אפשרות setsockopt() ברמת IPPROTO_IP.

socket.IP_DROP_MEMBERSHIP: int#

עזיבת קבוצת multicast. אפשרות setsockopt() ברמת IPPROTO_IP.

socket.TCP_NODELAY: int#

השבתת האלגוריתם של Nagle. אפשרות setsockopt() ברמת IPPROTO_TCP.

socket.MSG_PEEK: int#

עבור recv() / recvfrom(): מחזיר נתונים מבלי להסירם מתור הקלט.

socket.MSG_DONTWAIT: int#

עבור recv() / recvfrom(): מבצע את הפעולה במצב ללא חסימה.

מחלקות#

class socket.socket(af: int = AF_INET, type: int = SOCK_STREAM, proto: int = IPPROTO_TCP, /)#

יוצר socket חדש באמצעות משפחת הכתובות, סוג ה-socket ומספר הפרוטוקול הנתונים. ציון proto אינו נדרש ברוב המקרים (ואינו מומלץ); ארגומנט ה-type בוחר את הפרוטוקול הדרוש אוטומטית:

# Create STREAM TCP socket
socket(AF_INET, SOCK_STREAM)
# Create DGRAM UDP socket
socket(AF_INET, SOCK_DGRAM)
close() None#

מסמן את ה-socket כסגור ומשחרר את כל המשאבים. ברגע שזה קורה, כל הפעולות העתידיות על אובייקט ה-socket ייכשלו. הקצה המרוחק יקבל חיווי EOF אם הפרוטוקול תומך בכך.

sockets נסגרים אוטומטית כאשר הם נאספים על ידי איסוף הזבל, אך מומלץ לסגור אותם במפורש באמצעות close() מיד עם סיום העבודה איתם.

bind(address: Any) None#

קושר את ה-socket ל-address. ה-socket אסור שיהיה כבר קשור.

listen(backlog: int = 2) None#

מאפשר לשרת לקבל חיבורים. אם backlog מצוין, הוא חייב להיות לפחות 0 (אם הוא נמוך יותר, הוא ייקבע ל-0); והוא מציין את מספר החיבורים שלא התקבלו שהמערכת תאפשר לפני שתסרב לחיבורים חדשים. אם אינו מצוין, נבחר ערך סביר כברירת מחדל.

accept() Tuple['socket', Tuple]#

מקבל חיבור. ה-socket חייב להיות קשור לכתובת ולהאזין לחיבורים. ערך ההחזרה הוא זוג (conn, address) כאשר conn הוא אובייקט socket חדש שניתן להשתמש בו לשליחה ולקבלה של נתונים בחיבור, ו-address היא הכתובת הקשורה ל-socket בקצה השני של החיבור.

connect(address: Any) None#

מתחבר ל-socket מרוחק בכתובת address.

send(bytes: bytes) int#

שולח נתונים ל-socket. ה-socket חייב להיות מחובר ל-socket מרוחק. מחזיר את מספר הבייטים שנשלחו, שעשוי להיות קטן מאורך הנתונים (”short write“).

sendall(bytes: bytes) None#

שולח את כל הנתונים ל-socket. ה-socket חייב להיות מחובר ל-socket מרוחק. בניגוד ל-send(), מתודה זו תנסה לשלוח את כל הנתונים, על ידי שליחת הנתונים מקטע אחר מקטע ברצף.

התנהגות מתודה זו על sockets ללא חסימה אינה מוגדרת. עקב כך, ב-MicroPython, מומלץ להשתמש במתודה write() במקום, אשר בעלת אותה מדיניות ”ללא short writes“ עבור sockets חוסמים, ותחזיר את מספר הבייטים שנשלחו עבור sockets ללא חסימה.

recv(bufsize: int, flags: int = 0) bytes#

מקבל נתונים מה-socket. ערך ההחזרה הוא אובייקט bytes המייצג את הנתונים שהתקבלו. הכמות המרבית של נתונים שתתקבל בבת אחת מצוינת על ידי bufsize.

הארגומנט האופציונלי flags הוא OR ביטווייז של דגלי הודעה (MSG_PEEK, MSG_DONTWAIT), בעלי אותה משמעות כמו ב-CPython.

sendto(bytes: bytes, address: Any) int#

שולח נתונים ל-socket. ה-socket אינו אמור להיות מחובר ל-socket מרוחק, מכיוון שה-socket היעד מצוין על ידי address.

recvfrom(bufsize: int, flags: int = 0) Tuple[bytes, Tuple]#

מקבל נתונים מה-socket. ערך ההחזרה הוא זוג (bytes, address) כאשר bytes הוא אובייקט bytes המייצג את הנתונים שהתקבלו ו-address היא הכתובת של ה-socket השולח את הנתונים.

ראו את הפונקציה recv() להסבר על הארגומנט האופציונלי flags.

setsockopt(level: int, optname: int, value: int | bytes) None#

מגדיר את הערך של אפשרות ה-socket הנתונה. הקבועים הסמליים הדרושים מוגדרים במודול socket (SO_* וכו«). ה-value יכול להיות מספר שלם או אובייקט דמוי bytes המייצג חוצץ (buffer).

settimeout(value: float | None) None#

מגדיר פסק זמן על פעולות socket חוסמות. ארגומנט הערך יכול להיות מספר נקודה צפה אי-שלילי המבטא שניות, או None. אם ניתן ערך שאינו אפס, פעולות socket עוקבות יעלו חריגת OSError אם תקופת פסק הזמן חלפה לפני שהפעולה הושלמה. אם ניתן אפס, ה-socket מועבר למצב ללא חסימה. אם ניתן None, ה-socket מועבר למצב חוסם.

חלופה ניידת וכללית היא להשתמש באובייקט select.poll. זה מאפשר המתנה למספר אובייקטים בו-זמנית (ולא רק ל-sockets, אלא לאובייקטי stream כלליים התומכים ב-polling). דוגמה:

# Instead of:
s.settimeout(1.0)  # time in seconds
s.read(10)  # may timeout

# Use:
poller = select.poll()
poller.register(s, select.POLLIN)
res = poller.poll(1000)  # time in milliseconds
if not res:
    # s is still not ready for input, i.e. operation timed out

הבדל מ-CPython

CPython מעלה חריגת socket.timeout במקרה של פסק זמן, שהיא תת-מחלקה של OSError. במקום זאת, MicroPython מעלה OSError ישירות. אם תשתמשו ב-except OSError: כדי לתפוס את החריגה, הקוד שלכם יעבוד הן ב-MicroPython והן ב-CPython.

setblocking(flag: bool) None#

מגדיר מצב חוסם או ללא חסימה של ה-socket: אם flag הוא false, ה-socket נקבע למצב ללא חסימה, אחרת למצב חוסם.

מתודה זו היא קיצור עבור קריאות settimeout() מסוימות:

  • sock.setblocking(True) שקול ל-sock.settimeout(None)

  • sock.setblocking(False) שקול ל-sock.settimeout(0)

makefile(mode: str = 'rb', buffering: int = 0, /) Any#

מחזיר אובייקט קובץ המשויך ל-socket. הסוג המדויק המוחזר תלוי בארגומנטים שניתנו ל-makefile(). התמיכה מוגבלת למצבים בינאריים בלבד (»rb«, »wb«, ו-»rwb«). הארגומנטים של CPython: encoding, errors ו-newline אינם נתמכים.

הבדל מ-CPython

מכיוון ש-MicroPython אינו תומך בזרמים מאוחסנים בחוצץ (buffered), ערכי הפרמטר buffering מתעלמים מהם ומתייחסים אליהם כאילו היו 0 (ללא חוצץ).

הבדל מ-CPython

סגירת אובייקט הקובץ המוחזר על ידי makefile() תסגור גם את ה-socket המקורי.

read(size: int | None = None) bytes#

קורא עד size בייטים מה-socket. מחזיר אובייקט bytes. אם size אינו ניתן, הוא קורא את כל הנתונים הזמינים מה-socket עד EOF; ככזה, המתודה לא תחזור עד שה-socket ייסגר. פונקציה זו מנסה לקרוא כמה שיותר נתונים כמבוקש (ללא ”short reads“). ייתכן שזה לא יתאפשר עם socket ללא חסימה, ואז יוחזרו פחות נתונים.

readinto(buf: bytearray | memoryview, nbytes: int | None = None) int#

קורא בייטים לתוך buf. אם nbytes מצוין אז קורא לכל היותר אותו מספר בייטים. אחרת, קורא לכל היותר len(buf) בייטים. בדיוק כמו read(), מתודה זו עוקבת אחר מדיניות ”ללא short reads“.

ערך החזרה: מספר הבייטים שנקראו ואוחסנו לתוך buf.

readline() bytes#

קורא שורה, המסתיימת בתו שורה חדשה.

ערך החזרה: השורה שנקראה.

write(buf: bytes) int#

כותב את חוצץ הבייטים ל-socket. פונקציה זו תנסה לכתוב את כל הנתונים ל-socket (ללא ”short writes“). ייתכן שזה לא יתאפשר עם socket ללא חסימה, והערך המוחזר יהיה קטן מאורך buf.

ערך החזרה: מספר הבייטים שנכתבו.

הערה

MicroPython אינו מממש socket.error. ל-CPython יש חריגת socket.error שאינה מומלצת לשימוש שהיא כינוי של OSError; ב-MicroPython, השתמשו ב-OSError ישירות כדי לתפוס שגיאות הקשורות ל-socket.