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()จะแทนด้วยตัวเลขลบ ในขณะที่ข้อผิดพลาดระบบมาตรฐานเป็นตัวเลขบวก (สามารถเข้าถึงหมายเลขข้อผิดพลาดได้โดยใช้ propertye.args[0]จากออบเจกต์ exception) การใช้ค่าลบเป็นรายละเอียดเชิงทดสอบที่อาจเปลี่ยนแปลงได้ในอนาคต
ค่าคงที่¶
- socket.IPPROTO_IP: int¶
ระดับโปรโตคอล IP ใช้เป็นอาร์กิวเมนต์ level ใน
setsockopt()ร่วมกับ optionIP_*
- socket.IPPROTO_TCP: int¶
โปรโตคอล TCP ไม่จำเป็นต้องส่งให้
socket(ประเภท socketSOCK_STREAMเลือกให้อัตโนมัติ) การใช้งานจริงเพียงอย่างเดียวคือเป็นอาร์กิวเมนต์ level ในsetsockopt()ร่วมกับ optionTCP_*
- socket.SOL_SOCKET: int¶
ระดับ socket option ใช้เป็นอาร์กิวเมนต์ level ใน
setsockopt()ร่วมกับ optionSO_*
- 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()อย่างชัดเจนทันทีที่ใช้งานเสร็จ
- listen(backlog: int = 2) None¶
เปิดใช้งานเซิร์ฟเวอร์ให้รับการเชื่อมต่อ หาก backlog ถูกระบุ ต้องมีค่าอย่างน้อย 0 (หากต่ำกว่าจะถูกตั้งเป็น 0) และระบุจำนวนการเชื่อมต่อที่ยังไม่ได้รับที่ระบบจะอนุญาตก่อนปฏิเสธการเชื่อมต่อใหม่ หากไม่ระบุจะเลือกค่าที่เหมาะสมโดยอัตโนมัติ
- accept() Tuple['socket', Tuple]¶
รับการเชื่อมต่อ socket ต้องถูกผูกกับที่อยู่และกำลังฟังการเชื่อมต่อ ค่าที่ส่งคืนเป็นคู่ (conn, address) โดยที่ conn คือออบเจกต์ socket ใหม่ที่ใช้ส่งและรับข้อมูลบนการเชื่อมต่อ และ address คือที่อยู่ที่ผูกกับ socket ที่ปลายอีกด้านของการเชื่อมต่อ
- 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 ของOSErrorMicroPython 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 อาจทำไม่ได้และจะส่งคืนข้อมูลน้อยกว่า