socket --- وحدة المقابس (socket)¶
توفّر هذه الوحدة الوصول إلى واجهة مقابس BSD.
الاختلاف عن CPython
تحقيقًا للكفاءة والاتساق، تنفّذ كائنات المقابس في MicroPython واجهة stream (شبيهة بالملف) مباشرةً. أما في CPython، فعليك تحويل المقبس إلى كائن شبيه بالملف باستخدام الدالة makefile(). ولا تزال هذه الدالة مدعومة في MicroPython (لكنها لا تؤدي أي عمل)، لذا حيثما كان التوافق مع CPython مهمًا، احرص على استخدامها.
صيغة (صيغ) عنوان المقبس¶
صيغة عنوان المقبس الأصلية لوحدة 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 مدمجة؛ ويمكن إعطاء العناوين العددية مباشرةً بصيغة الصف، لكن يجب أولًا حل أسماء النطاقات باستخدام getaddrinfo().
خلاصة القول:
استخدم دائمًا
getaddrinfo()لحل أسماء المضيفين.يمكن استخدام عناوين الصفوف الموضحة أدناه كاختصار للعناوين العددية، لأغراض الحلول السريعة والاستخدام التفاعلي.
صيغة عنوان الصف لوحدة 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 صفرًا. وscopeid هو معرّف نطاق الواجهة للعناوين المحلية للوصلة. ولا تُقبل أسماء النطاقات كـ ipv6_address؛ فحلّها أولًا باستخدامgetaddrinfo().
الدوال¶
- socket.getaddrinfo(host: str, port: int, af: int = 0, type: int = 0, proto: int = 0, flags: int = 0, /) List[Tuple]¶
يترجم وسيط المضيف/المنفذ إلى سلسلة من الصفوف الخماسية التي تحتوي على جميع الوسائط اللازمة لإنشاء مقبس متصل بتلك الخدمة. يمكن استخدام الوسائط af وtype وproto (التي لها المعنى نفسه كما في الدالة
socket) لتصفية أنواع العناوين التي تُرجَع. وإذا لم يُحدّد معامل أو كان صفرًا، فقد تُرجَع جميع تركيبات العناوين (مما يتطلب التصفية من جانب المستخدم).تكون قائمة الصفوف الخماسية الناتجة بالبنية التالية:
(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.IPPROTO_IP: int¶
مستوى بروتوكول IP. يُستخدم كوسيط level للدالة
setsockopt()مع خياراتIP_*.
- socket.IPPROTO_TCP: int¶
بروتوكول TCP. لست بحاجة إلى تمريره إلى
socket(إذ يختاره نوع المقبسSOCK_STREAMتلقائيًا)؛ واستخدامه الفعلي الوحيد هو كوسيط level للدالةsetsockopt()مع خياراتTCP_*.
- socket.SOL_SOCKET: int¶
مستوى خيار المقبس. يُستخدم كوسيط level للدالة
setsockopt()مع خياراتSO_*.
- socket.SO_SNDTIMEO: int¶
مهلة الإرسال، بالميلي ثانية، تُمرَّر كوسيط value للدالة
setsockopt().
- socket.SO_RCVTIMEO: int¶
مهلة الاستقبال، بالميلي ثانية، تُمرَّر كوسيط value للدالة
setsockopt().
- socket.IP_ADD_MEMBERSHIP: int¶
ينضم إلى مجموعة بث متعدد. خيار من مستوى
IPPROTO_IPللدالةsetsockopt().
- socket.IP_DROP_MEMBERSHIP: int¶
يغادر مجموعة بث متعدد. خيار من مستوى
IPPROTO_IPللدالةsetsockopt().
- socket.TCP_NODELAY: int¶
يعطّل خوارزمية Nagle. خيار من مستوى
IPPROTO_TCPللدالةsetsockopt().
- 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, /)¶
ينشئ مقبسًا جديدًا باستخدام عائلة العناوين ونوع المقبس ورقم البروتوكول المعطاة. وتحديد proto غير مطلوب في معظم الحالات (وغير موصى به)؛ إذ يختار وسيط type البروتوكول اللازم تلقائيًا:
# Create STREAM TCP socket socket(AF_INET, SOCK_STREAM) # Create DGRAM UDP socket socket(AF_INET, SOCK_DGRAM)
- close() None¶
يضع علامة على المقبس بأنه مغلق ويحرّر جميع الموارد. وبمجرد حدوث ذلك، ستفشل جميع العمليات المستقبلية على كائن المقبس. وسيتلقى الطرف البعيد إشارة EOF إذا كان البروتوكول يدعم ذلك.
تُغلق المقابس تلقائيًا عند جمعها بآلية كنس المهملات، لكن يُوصى بإغلاقها صراحةً بـ
close()بمجرد الانتهاء من العمل بها.
- listen(backlog: int = 2) None¶
يمكّن خادمًا من قبول الاتصالات. وإذا حُدّد backlog فيجب أن يكون 0 على الأقل (وإذا كان أقل، فسيُضبط إلى 0)؛ وهو يحدد عدد الاتصالات غير المقبولة التي سيسمح بها النظام قبل رفض الاتصالات الجديدة. وإذا لم يُحدّد، فسيُختار قيمة افتراضية معقولة.
- accept() Tuple['socket', Tuple]¶
يقبل اتصالًا. يجب أن يكون المقبس مرتبطًا بعنوان ومنصتًا للاتصالات. والقيمة المُرجَعة زوج (conn, address) حيث conn كائن مقبس جديد قابل للاستخدام لإرسال البيانات واستقبالها على الاتصال، وaddress هو العنوان المرتبط بالمقبس على الطرف الآخر من الاتصال.
- send(bytes: bytes) int¶
يرسل بيانات إلى المقبس. يجب أن يكون المقبس متصلًا بمقبس بعيد. يُرجع عدد البايتات المُرسَلة، الذي قد يكون أصغر من طول البيانات ("كتابة قصيرة").
- sendall(bytes: bytes) None¶
يرسل جميع البيانات إلى المقبس. يجب أن يكون المقبس متصلًا بمقبس بعيد. وخلافًا لـ
send()، ستحاول هذه الدالة إرسال جميع البيانات، بإرسالها قطعة قطعة على التوالي.سلوك هذه الدالة على المقابس غير الحاجبة غير معرّف. ولهذا السبب، يُوصى في MicroPython باستخدام الدالة
write()بدلًا منها، التي تتبع سياسة "بلا كتابات قصيرة" نفسها للمقابس الحاجبة، وتُرجع عدد البايتات المُرسَلة على المقابس غير الحاجبة.
- recv(bufsize: int, flags: int = 0) bytes¶
يستقبل بيانات من المقبس. والقيمة المُرجَعة كائن بايتات يمثّل البيانات المستقبَلة. ويُحدّد bufsize الحد الأقصى لكمية البيانات التي يمكن استقبالها دفعةً واحدة.
وسيط flags الاختياري هو OR على مستوى البتات لأعلام الرسائل (
MSG_PEEKوMSG_DONTWAIT)، التي لها المعنى نفسه كما في CPython.
- sendto(bytes: bytes, address: Any) int¶
يرسل بيانات إلى المقبس. يجب ألا يكون المقبس متصلًا بمقبس بعيد، إذ يُحدَّد مقبس الوجهة بواسطة address.
- recvfrom(bufsize: int, flags: int = 0) Tuple[bytes, Tuple]¶
يستقبل بيانات من المقبس. والقيمة المُرجَعة زوج (bytes, address) حيث bytes كائن بايتات يمثّل البيانات المستقبَلة وaddress هو عنوان المقبس الذي يرسل البيانات.
راجع الدالة
recv()لشرح وسيط flags الاختياري.
- setsockopt(level: int, optname: int, value: int | bytes) None¶
يضبط قيمة خيار المقبس المعطى. الثوابت الرمزية اللازمة معرّفة في وحدة socket (SO_* وغيرها). ويمكن أن تكون value عددًا صحيحًا أو كائنًا شبيهًا بالبايتات يمثّل مخزنًا مؤقتًا.
- settimeout(value: float | None) None¶
يضبط مهلة على عمليات المقبس الحاجبة. يمكن أن يكون وسيط القيمة عددًا عشريًا غير سالب يعبّر عن الثواني، أو None. وإذا أُعطيت قيمة غير صفرية، فستثير عمليات المقبس اللاحقة استثناء
OSErrorإذا انقضت قيمة فترة المهلة قبل اكتمال العملية. وإذا أُعطي صفر، يوضع المقبس في الوضع غير الحاجب. وإذا أُعطيت None، يوضع المقبس في الوضع الحاجب.البديل القابل للنقل والعام هو استخدام كائن
select.poll. وهذا يتيح الانتظار على كائنات متعددة في الوقت نفسه (وليس على المقابس فحسب، بل على كائنات stream العامة التي تدعم الاستطلاع). مثال:# 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¶
يضبط الوضع الحاجب أو غير الحاجب للمقبس: إذا كان flag خطأً (false)، يُضبط المقبس على الوضع غير الحاجب، وإلا فعلى الوضع الحاجب.
هذه الدالة اختصار لاستدعاءات
settimeout()معينة:sock.setblocking(True)يكافئsock.settimeout(None)sock.setblocking(False)يكافئsock.settimeout(0)
- makefile(mode: str = 'rb', buffering: int = 0, /) Any¶
يُرجع كائن ملف مرتبطًا بالمقبس. ويعتمد النوع المُرجَع بالضبط على الوسائط المعطاة لـ makefile(). والدعم مقتصر على الأوضاع الثنائية فقط ('rb' و'wb' و'rwb'). أما وسائط CPython: encoding وerrors وnewline فغير مدعومة.
الاختلاف عن CPython
بما أن MicroPython لا يدعم الدفق المخزَّن مؤقتًا، فإن قيم المعامل buffering تُتجاهل وتُعامَل كأنها 0 (غير مخزَّن مؤقتًا).
الاختلاف عن CPython
إغلاق كائن الملف المُرجَع من makefile() سيُغلق المقبس الأصلي أيضًا.
- read(size: int | None = None) bytes¶
يقرأ ما يصل إلى size بايتًا من المقبس. ويُرجع كائن بايتات. وإذا لم تُعطَ size، فإنه يقرأ جميع البيانات المتاحة من المقبس حتى EOF؛ وبالتالي لن تُرجع الدالة حتى يُغلق المقبس. وتحاول هذه الدالة قراءة أكبر قدر ممكن من البيانات المطلوبة (بلا "قراءات قصيرة"). غير أن ذلك قد لا يكون ممكنًا مع المقبس غير الحاجب، وعندها ستُرجَع بيانات أقل.
- readinto(buf: bytearray | memoryview, nbytes: int | None = None) int¶
يقرأ بايتات إلى buf. وإذا حُدّد nbytes، فإنه يقرأ على الأكثر ذلك العدد من البايتات. وإلا، فإنه يقرأ على الأكثر len(buf) بايتًا. وتمامًا كـ
read()، تتبع هذه الدالة سياسة "بلا قراءات قصيرة".القيمة المُرجَعة: عدد البايتات المقروءة والمخزَّنة في buf.