socket --- socket module

โมดูลนี้ให้การเข้าถึง BSD socket interface

ความแตกต่างจาก CPython

เพื่อประสิทธิภาพและความสอดคล้อง ออบเจกต์ socket ใน MicroPython ใช้งาน stream (คล้ายไฟล์) interface โดยตรง ใน CPython คุณต้องแปลง socket เป็นออบเจกต์คล้ายไฟล์โดยใช้เมธอด makefile() เมธอดนี้ยังคงรองรับใน MicroPython (แต่ไม่ทำอะไร) ดังนั้นหากความเข้ากันได้กับ CPython มีความสำคัญ ให้แน่ใจว่าใช้เมธอดนั้น

รูปแบบที่อยู่ socket

รูปแบบที่อยู่ socket แบบ native ของโมดูล 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 ในการระบุที่อยู่โดยใช้ tuple ตามที่อธิบายด้านล่าง บน OpenMV Cam โมดูล socket ถูกติดตั้งไว้แล้ว สามารถระบุที่อยู่ตัวเลขโดยตรงในรูปแบบ tuple ได้ แต่ domain name ต้องแปลงด้วย getaddrinfo() ก่อน

สรุป:

  • ใช้ getaddrinfo() เสมอเพื่อแปลง host name

  • ที่อยู่แบบ tuple ที่อธิบายด้านล่างสามารถใช้เป็นทางลัดสำหรับที่อยู่ตัวเลข สำหรับการทดสอบอย่างรวดเร็วและการใช้งานแบบโต้ตอบ

รูปแบบที่อยู่ tuple สำหรับโมดูล socket:

  • IPv4: (ipv4_address, port) โดยที่ ipv4_address เป็น string ที่มีที่อยู่ IPv4 ตัวเลขแบบจุด เช่น "8.8.8.8" และ port เป็นหมายเลข port จำนวนเต็มในช่วง 1-65535 ไม่รองรับ domain name เป็น ipv4_address ให้แปลงก่อนโดยใช้ getaddrinfo()

  • IPv6: (ipv6_address, port, flowinfo, scopeid) โดยที่ ipv6_address เป็น string ที่มีที่อยู่ IPv6 ตัวเลขแบบโคลอน เช่น "2001:db8::1" และ port เป็นหมายเลข port จำนวนเต็มในช่วง 1-65535 flowinfo ต้องเป็น 0 scopeid คือตัวระบุขอบเขต interface สำหรับที่อยู่ link-local ไม่รองรับ domain name เป็น ipv6_address ให้แปลงก่อนโดยใช้ getaddrinfo()

ฟังก์ชัน

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

แปล argument host/port เป็นลำดับ 5-tuple ที่มีอาร์กิวเมนต์ที่จำเป็นทั้งหมดสำหรับการสร้าง socket ที่เชื่อมต่อกับบริการนั้น อาร์กิวเมนต์ af, type และ proto (ซึ่งมีความหมายเหมือนกับฟังก์ชัน socket) สามารถใช้กรองว่าจะส่งคืนที่อยู่ประเภทใด หากไม่ระบุพารามิเตอร์หรือเป็นศูนย์ อาจส่งคืนทุกการรวมกันของที่อยู่ (ต้องกรองเองที่ฝั่ง user)

รายการ 5-tuple ที่ได้มีโครงสร้างดังนี้:

(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 raise exception socket.gaierror (subclass ของ OSError) ในกรณีที่เกิดข้อผิดพลาดในฟังก์ชันนี้ MicroPython ไม่มี socket.gaierror และ raise OSError โดยตรง โปรดทราบว่าหมายเลขข้อผิดพลาดของ getaddrinfo() เป็น namespace แยกต่างหากและอาจไม่ตรงกับหมายเลขข้อผิดพลาดจากโมดูล errno เพื่อแยกแยะข้อผิดพลาดของ getaddrinfo() จะแทนด้วยตัวเลขลบ ในขณะที่ข้อผิดพลาดระบบมาตรฐานเป็นตัวเลขบวก (สามารถเข้าถึงหมายเลขข้อผิดพลาดได้โดยใช้ property e.args[0] จากออบเจกต์ exception) การใช้ค่าลบเป็นรายละเอียดเชิงทดสอบที่อาจเปลี่ยนแปลงได้ในอนาคต

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

แปลงที่อยู่เครือข่ายไบนารี bin_addr ของ address family 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 ของ address family af ที่กำหนดเป็นรูปแบบไบนารี:

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

ค่าคงที่

socket.AF_INET: int

IPv4 address family

socket.AF_INET6: int

IPv6 address family

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() ร่วมกับ option IP_*

socket.IPPROTO_TCP: int

โปรโตคอล TCP ไม่จำเป็นต้องส่งให้ socket (ประเภท socket SOCK_STREAM เลือกให้อัตโนมัติ) การใช้งานจริงเพียงอย่างเดียวคือเป็นอาร์กิวเมนต์ level ใน setsockopt() ร่วมกับ option TCP_*

socket.SOL_SOCKET: int

ระดับ socket option ใช้เป็นอาร์กิวเมนต์ level ใน setsockopt() ร่วมกับ option SO_*

socket.SO_REUSEADDR: int

อนุญาตให้ socket ผูกกับที่อยู่/port ที่ยังอยู่ในสถานะ TIME_WAIT

socket.SO_BROADCAST: int

อนุญาตให้ส่ง datagram ไปยังที่อยู่ broadcast

socket.SO_KEEPALIVE: int

เปิดใช้งานการส่ง keep-alive probe เป็นระยะบน socket ที่เชื่อมต่อแล้ว

socket.SO_SNDTIMEO: int

timeout การส่ง หน่วยเป็นมิลลิวินาที ส่งเป็นอาร์กิวเมนต์ value ใน setsockopt()

socket.SO_RCVTIMEO: int

timeout การรับ หน่วยเป็นมิลลิวินาที ส่งเป็นอาร์กิวเมนต์ value ใน setsockopt()

socket.IP_ADD_MEMBERSHIP: int

เข้าร่วม multicast group เป็น option setsockopt() ระดับ IPPROTO_IP

socket.IP_DROP_MEMBERSHIP: int

ออกจาก multicast group เป็น option setsockopt() ระดับ IPPROTO_IP

socket.TCP_NODELAY: int

ปิดใช้งาน Nagle's algorithm เป็น option setsockopt() ระดับ IPPROTO_TCP

socket.MSG_PEEK: int

สำหรับ recv() / recvfrom(): ส่งคืนข้อมูลโดยไม่ลบออกจาก input queue

socket.MSG_DONTWAIT: int

สำหรับ recv() / recvfrom(): ดำเนินการในโหมด non-blocking

คลาส

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

สร้าง socket ใหม่โดยใช้ address family ประเภท 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 หากโปรโตคอลรองรับ

Socket จะถูกปิดโดยอัตโนมัติเมื่อถูก garbage-collect แต่แนะนำให้ 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 ระยะไกล ส่งคืนจำนวน byte ที่ส่ง ซึ่งอาจน้อยกว่าความยาวของข้อมูล ("short write")

sendall(bytes: bytes) None

ส่งข้อมูลทั้งหมดไปยัง socket socket ต้องเชื่อมต่อกับ socket ระยะไกล ต่างจาก send() เมธอดนี้จะพยายามส่งข้อมูลทั้งหมด โดยส่งข้อมูลทีละชิ้นต่อเนื่องกัน

พฤติกรรมของเมธอดนี้บน non-blocking socket ไม่ถูกกำหนด ด้วยเหตุนี้ใน MicroPython จึงแนะนำให้ใช้เมธอด write() แทน ซึ่งมีนโยบาย "no short writes" เหมือนกันสำหรับ blocking socket และจะส่งคืนจำนวน byte ที่ส่งสำหรับ non-blocking socket

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

รับข้อมูลจาก socket ค่าที่ส่งคืนเป็นออบเจกต์ bytes ที่แสดงข้อมูลที่ได้รับ ปริมาณข้อมูลสูงสุดที่จะรับในครั้งเดียวถูกระบุโดย bufsize

อาร์กิวเมนต์ flags เสริมเป็น bitwise OR ของ message flag (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 option ที่กำหนด ค่าคงที่สัญลักษณ์ที่จำเป็นถูกกำหนดในโมดูล socket (SO_* เป็นต้น) value อาจเป็นจำนวนเต็มหรือออบเจกต์คล้าย bytes ที่แสดง buffer

settimeout(value: float | None) None

ตั้งค่า timeout บน blocking socket operation ค่าอาร์กิวเมนต์อาจเป็นตัวเลขทศนิยมที่ไม่ติดลบซึ่งแสดงเป็นวินาที หรือ None หากให้ค่าที่ไม่ใช่ศูนย์ การดำเนินการ socket ต่อมาจะ raise exception OSError หากระยะเวลา timeout ผ่านไปก่อนที่การดำเนินการจะเสร็จสมบูรณ์ หากให้ค่าศูนย์ socket จะถูกตั้งในโหมด non-blocking หากให้ None socket จะถูกตั้งในโหมด blocking

ทางเลือกที่พกพาได้และทั่วไปคือการใช้ออบเจกต์ select.poll ซึ่งช่วยให้รอหลายออบเจกต์พร้อมกันได้ (ไม่ใช่แค่ socket แต่รวมถึงออบเจกต์ 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 raise exception socket.timeout ในกรณี timeout ซึ่งเป็น subclass ของ OSError MicroPython raise OSError โดยตรงแทน หากใช้ except OSError: เพื่อดักจับ exception โค้ดของคุณจะทำงานได้ทั้งใน MicroPython และ CPython

setblocking(flag: bool) None

ตั้งค่าโหมด blocking หรือ non-blocking ของ socket ถ้า flag เป็น false socket จะถูกตั้งเป็น non-blocking มิเช่นนั้นจะตั้งเป็น blocking mode

เมธอดนี้เป็นชวเลขสำหรับการเรียก settimeout() บางอย่าง:

  • sock.setblocking(True) เทียบเท่ากับ sock.settimeout(None)

  • sock.setblocking(False) เทียบเท่ากับ sock.settimeout(0)

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

ส่งคืนออบเจกต์ไฟล์ที่เชื่อมโยงกับ socket ประเภทที่ส่งคืนที่แน่นอนขึ้นอยู่กับอาร์กิวเมนต์ที่ให้กับ makefile() รองรับเฉพาะโหมด binary ('rb', 'wb' และ 'rwb') อาร์กิวเมนต์ของ CPython ได้แก่ encoding, errors และ newline ไม่รองรับ

ความแตกต่างจาก CPython

เนื่องจาก MicroPython ไม่รองรับ buffered stream ค่าของพารามิเตอร์ buffering จะถูกละเว้นและถือว่าเป็น 0 (unbuffered)

ความแตกต่างจาก CPython

การปิดออบเจกต์ไฟล์ที่ส่งคืนโดย makefile() จะปิด socket ต้นฉบับด้วย

read(size: int | None = None) bytes

อ่านข้อมูลสูงสุด size byte จาก socket ส่งคืนออบเจกต์ bytes หาก size ไม่ได้ระบุ จะอ่านข้อมูลทั้งหมดที่มีจาก socket จนถึง EOF ดังนั้นเมธอดจะไม่ส่งคืนจนกว่า socket จะปิด ฟังก์ชันนี้พยายามอ่านข้อมูลตามที่ร้องขอให้ได้มากที่สุด (ไม่มี "short reads") อย่างไรก็ตามกับ non-blocking socket อาจทำไม่ได้และจะส่งคืนข้อมูลน้อยกว่า

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

อ่าน byte เข้า buf หาก nbytes ถูกระบุจะอ่านสูงสุดตามจำนวนนั้น มิเช่นนั้นจะอ่านสูงสุด len(buf) byte เช่นเดียวกับ read() เมธอดนี้ตาม นโยบาย "no short reads"

ค่าที่ส่งคืน: จำนวน byte ที่อ่านและเก็บไว้ใน buf

readline() bytes

อ่าน 1 บรรทัด สิ้นสุดด้วยอักขระขึ้นบรรทัดใหม่

ค่าที่ส่งคืน: บรรทัดที่อ่าน

write(buf: bytes) int

เขียน buffer ของ byte ไปยัง socket ฟังก์ชันนี้จะพยายามเขียนข้อมูลทั้งหมดไปยัง socket (ไม่มี "short writes") อย่างไรก็ตามกับ non-blocking socket อาจทำไม่ได้ และค่าที่ส่งคืนจะน้อยกว่าความยาวของ buf

ค่าที่ส่งคืน: จำนวน byte ที่เขียน

Note

MicroPython ไม่ใช้งาน socket.error CPython มี exception socket.error ที่เลิกใช้แล้วซึ่งเป็น alias ของ OSError ใน MicroPython ให้ใช้ OSError โดยตรงเพื่อดักจับข้อผิดพลาดที่เกี่ยวข้องกับ socket