socket --- socket 模組¶
本模組提供對 BSD socket 介面的存取。
與 CPython 的差異
為了效率與一致性,MicroPython 中的 socket 物件直接實作了 stream(類檔案)介面。在 CPython 中,你需要使用 makefile() 方法將 socket 轉換為類檔案物件。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 相容、使用元組 (tuple) 指定位址的方式,如下所述。在 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 必須為 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]¶
將 host/port 引數轉換為一連串 5 元組,其中包含建立連接到該服務的 socket 所需的所有引數。引數 af、type 與 proto(其意義與
socket函式相同)可用於篩選回傳哪一種位址。若某參數未指定或為零,則可能回傳所有位址組合(需由使用者端自行篩選)。產生的 5 元組清單具有下列結構:
(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 引數,與
IP_*選項一起傳給setsockopt()。
- socket.IPPROTO_TCP: int¶
TCP 通訊協定。你不需要將它傳給
socket(SOCK_STREAMsocket 類型會自動選用它);它唯一的實際用途是作為 level 引數,與TCP_*選項一起傳給setsockopt()。
- socket.SOL_SOCKET: int¶
Socket 選項層級。作為 level 引數,與
SO_*選項一起傳給setsockopt()。
- 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, /)¶
使用給定的位址族系、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 指示。
Socket 在被記憶體回收時會自動關閉,但建議在你完成使用後盡快明確地
close()它們。
- listen(backlog: int = 2) None¶
讓伺服器能夠接受連線。若指定了 backlog,它必須至少為 0(若更低,則會設為 0);它指定系統在拒絕新連線之前所允許的未接受連線數量。若未指定,則會選用一個合理的預設值。
- accept() Tuple['socket', Tuple]¶
接受一個連線。該 socket 必須已繫結到某位址並正在監聽連線。回傳值是一對 (conn, address),其中 conn 是一個新的 socket 物件,可用於在該連線上傳送與接收資料,而 address 是連線另一端繫結到 socket 的位址。
- sendall(bytes: bytes) None¶
將所有資料傳送到 socket。該 socket 必須已連接到遠端 socket。與
send()不同,此方法會嘗試傳送所有資料,方法是將資料分塊連續傳送。此方法在非阻塞 socket 上的行為未定義。因此在 MicroPython 上建議改用
write()方法,它對阻塞 socket 採用相同的「無短寫入」策略,並在非阻塞 socket 上回傳已傳送的位元組數。
- recv(bufsize: int, flags: int = 0) bytes¶
從 socket 接收資料。回傳值是一個代表所接收資料的 bytes 物件。一次最多接收的資料量由 bufsize 指定。
選用的 flags 引數是訊息旗標 (
MSG_PEEK、MSG_DONTWAIT) 的位元 OR,其意義與 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 的位址。
關於選用的 flags 引數的說明,請參閱
recv()函式。
- setsockopt(level: int, optname: int, value: int | bytes) None¶
設定給定 socket 選項的值。所需的符號常數定義於 socket 模組中(SO_* 等)。value 可以是整數,或是代表緩衝區的類位元組物件。
- settimeout(value: float | None) None¶
在阻塞式 socket 操作上設定逾時。value 引數可以是表示秒數的非負浮點數,或 None。若給定非零值,則若逾時期限在操作完成前已過去,後續的 socket 操作會引發
OSError例外。若給定零,socket 會被置於非阻塞模式。若給定 None,socket 會被置於阻塞模式。一個可攜且通用的替代方式是使用
select.poll物件。它允許同時等待多個物件(不僅限於 socket,還包括支援輪詢的通用 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¶
設定 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 不支援緩衝串流,buffering 參數的值會被忽略,並視為 0(無緩衝)。
與 CPython 的差異
關閉由 makefile() 回傳的檔案物件「也會」一併關閉原本的 socket。
- read(size: int | None = None) bytes¶
從 socket 讀取至多 size 個位元組。回傳一個 bytes 物件。若未給定 size,則它會從 socket 讀取所有可用資料直到 EOF;因此此方法在 socket 關閉前不會回傳。此函式會嘗試讀取所要求的資料量(無「短讀取」)。不過在非阻塞 socket 上這可能無法做到,此時會回傳較少的資料。