socket --- mô-đun socket¶
Mô-đun này cung cấp quyền truy cập vào giao diện socket BSD.
Khác biệt so với CPython
Để đạt hiệu quả và nhất quán, các đối tượng socket trong MicroPython triển khai trực tiếp giao diện stream (giống file). Trong CPython, bạn cần chuyển đổi socket thành đối tượng giống file bằng phương thức makefile(). Phương thức này vẫn được MicroPython hỗ trợ (nhưng là no-op), vì vậy khi cần tương thích với CPython, hãy chắc chắn sử dụng nó.
Định dạng địa chỉ socket¶
Định dạng địa chỉ socket gốc của mô-đun socket là một kiểu dữ liệu mờ được trả về bởi hàm getaddrinfo(), hàm này phải được dùng để phân giải địa chỉ dạng văn bản (bao gồm địa chỉ số):
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)
Sử dụng getaddrinfo() là cách hiệu quả nhất (cả về bộ nhớ và sức mạnh xử lý) và di động nhất để làm việc với địa chỉ.
Mô-đun socket cũng cung cấp cách tương thích CPython để chỉ định địa chỉ bằng cách dùng tuple, như mô tả bên dưới. Trên OpenMV Cam, mô-đun socket được tích hợp sẵn; địa chỉ số có thể được cung cấp trực tiếp theo định dạng tuple, nhưng tên miền phải được phân giải trước bằng getaddrinfo().
Tóm tắt:
Luôn dùng
getaddrinfo()để phân giải tên máy chủ.Địa chỉ tuple được mô tả dưới đây có thể được sử dụng như lối tắt cho địa chỉ số, cho các thử nghiệm nhanh và sử dụng tương tác.
Định dạng địa chỉ tuple cho mô-đun socket:
IPv4: (ipv4_address, port), trong đó ipv4_address là chuỗi địa chỉ IPv4 số theo ký hiệu dấu chấm, ví dụ:
"8.8.8.8", và port là số nguyên cổng trong phạm vi 1-65535. Tên miền không được chấp nhận làm ipv4_address; hãy phân giải chúng trước bằnggetaddrinfo().IPv6: (ipv6_address, port, flowinfo, scopeid), trong đó ipv6_address là chuỗi địa chỉ IPv6 số theo ký hiệu dấu hai chấm, ví dụ:
"2001:db8::1", và port là số nguyên cổng trong phạm vi 1-65535. flowinfo phải là 0. scopeid là mã định danh phạm vi giao diện cho các địa chỉ link-local. Tên miền không được chấp nhận làm ipv6_address; hãy phân giải chúng trước bằnggetaddrinfo().
Các hàm¶
- socket.getaddrinfo(host: str, port: int, af: int = 0, type: int = 0, proto: int = 0, flags: int = 0, /) List[Tuple]¶
Dịch đối số host/port thành một chuỗi các 5-tuple chứa tất cả các đối số cần thiết để tạo socket kết nối đến dịch vụ đó. Các đối số af, type và proto (có cùng nghĩa như đối với hàm
socket) có thể được dùng để lọc loại địa chỉ nào được trả về. Nếu một tham số không được chỉ định hoặc bằng không, tất cả các kết hợp địa chỉ có thể được trả về (yêu cầu lọc ở phía người dùng).Danh sách kết quả gồm các 5-tuple có cấu trúc sau:
(family, type, proto, canonname, sockaddr)Ví dụ sau đây cho thấy cách kết nối đến một url đã cho:
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])
Cách sử dụng được khuyến nghị của các tham số lọc:
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])
Khác biệt so với CPython
CPython gây ra ngoại lệ
socket.gaierror(lớp con củaOSError) trong trường hợp lỗi trong hàm này. MicroPython không cósocket.gaierrorvà gây ra OSError trực tiếp. Lưu ý rằng các số lỗi củagetaddrinfo()tạo thành một không gian tên riêng biệt và có thể không khớp với các số lỗi từ mô-đunerrno. Để phân biệt các lỗi củagetaddrinfo(), chúng được biểu diễn bằng các số âm, trong khi các lỗi hệ thống tiêu chuẩn là các số dương (các số lỗi có thể truy cập bằng thuộc tínhe.args[0]từ đối tượng ngoại lệ). Việc sử dụng các giá trị âm là một chi tiết tạm thời có thể thay đổi trong tương lai.
Các hằng số¶
- socket.IPPROTO_IP: int¶
Cấp độ giao thức IP. Được dùng làm đối số level cho
setsockopt()cùng với các tùy chọnIP_*.
- socket.IPPROTO_TCP: int¶
Giao thức TCP. Bạn không cần truyền cái này cho
socket(kiểu socketSOCK_STREAMtự động chọn nó); chỉ có mục đích thực sự duy nhất là làm đối số level chosetsockopt()cùng với các tùy chọnTCP_*.
- socket.SOL_SOCKET: int¶
Cấp độ tùy chọn socket. Được dùng làm đối số level cho
setsockopt()cùng với các tùy chọnSO_*.
- socket.SO_REUSEADDR: int¶
Cho phép socket kết buộc với một địa chỉ/cổng vẫn còn ở trạng thái
TIME_WAIT.
- socket.SO_SNDTIMEO: int¶
Thời gian chờ gửi, tính bằng mili giây, được truyền vào như đối số value cho
setsockopt().
- socket.SO_RCVTIMEO: int¶
Thời gian chờ nhận, tính bằng mili giây, được truyền vào như đối số value cho
setsockopt().
- socket.IP_ADD_MEMBERSHIP: int¶
Tham gia một nhóm multicast. Tùy chọn
setsockopt()cấpIPPROTO_IP.
- socket.IP_DROP_MEMBERSHIP: int¶
Rời khỏi một nhóm multicast. Tùy chọn
setsockopt()cấpIPPROTO_IP.
- socket.TCP_NODELAY: int¶
Tắt thuật toán Nagle. Tùy chọn
setsockopt()cấpIPPROTO_TCP.
- socket.MSG_PEEK: int¶
Cho
recv()/recvfrom(): trả về dữ liệu mà không xóa nó khỏi hàng đợi đầu vào.
- socket.MSG_DONTWAIT: int¶
Cho
recv()/recvfrom(): thực hiện thao tác ở chế độ không chặn.
Các lớp¶
- class socket.socket(af: int = AF_INET, type: int = SOCK_STREAM, proto: int = IPPROTO_TCP, /)¶
Tạo một socket mới bằng cách sử dụng họ địa chỉ, kiểu socket và số giao thức đã cho. Chỉ định proto trong hầu hết các trường hợp là không cần thiết (và không được khuyến nghị); đối số type tự động chọn giao thức cần thiết:
# Create STREAM TCP socket socket(AF_INET, SOCK_STREAM) # Create DGRAM UDP socket socket(AF_INET, SOCK_DGRAM)
- close() None¶
Đánh dấu socket đóng và giải phóng tất cả tài nguyên. Sau khi điều đó xảy ra, tất cả các thao tác tương lai trên đối tượng socket sẽ thất bại. Phía cuối từ xa sẽ nhận chỉ báo EOF nếu được giao thức hỗ trợ.
Các socket được tự động đóng khi chúng được thu gom rác, nhưng được khuyến nghị
close()chúng một cách rõ ràng ngay khi bạn hoàn thành việc làm việc với chúng.
- listen(backlog: int = 2) None¶
Bật máy chủ để chấp nhận kết nối. Nếu backlog được chỉ định, nó phải ít nhất là 0 (nếu nhỏ hơn, nó sẽ được đặt thành 0); và chỉ định số lượng kết nối chưa được chấp nhận mà hệ thống sẽ cho phép trước khi từ chối kết nối mới. Nếu không được chỉ định, một giá trị mặc định hợp lý sẽ được chọn.
- accept() Tuple['socket', Tuple]¶
Chấp nhận một kết nối. Socket phải được kết buộc với một địa chỉ và đang lắng nghe kết nối. Giá trị trả về là một cặp (conn, address) trong đó conn là đối tượng socket mới có thể dùng để gửi và nhận dữ liệu trên kết nối, và address là địa chỉ được kết buộc với socket ở phía còn lại của kết nối.
- send(bytes: bytes) int¶
Gửi dữ liệu đến socket. Socket phải được kết nối đến socket từ xa. Trả về số byte đã gửi, có thể nhỏ hơn độ dài dữ liệu ("ghi ngắn").
- sendall(bytes: bytes) None¶
Gửi tất cả dữ liệu đến socket. Socket phải được kết nối đến socket từ xa. Không giống như
send(), phương thức này sẽ cố gắng gửi tất cả dữ liệu, bằng cách gửi dữ liệu theo từng đoạn liên tiếp.Hành vi của phương thức này trên các socket không chặn là không xác định. Do đó, trên MicroPython, được khuyến nghị sử dụng phương thức
write()thay thế, có cùng chính sách "không ghi ngắn" cho các socket chặn, và sẽ trả về số byte đã gửi trên các socket không chặn.
- recv(bufsize: int, flags: int = 0) bytes¶
Nhận dữ liệu từ socket. Giá trị trả về là đối tượng bytes đại diện cho dữ liệu đã nhận. Lượng dữ liệu tối đa cần nhận mỗi lần được chỉ định bởi bufsize.
Đối số flags tùy chọn là OR theo bit của các cờ tin nhắn (
MSG_PEEK,MSG_DONTWAIT), có cùng nghĩa như trong CPython.
- sendto(bytes: bytes, address: Any) int¶
Gửi dữ liệu đến socket. Socket không nên được kết nối đến socket từ xa, vì socket đích được chỉ định bởi address.
- recvfrom(bufsize: int, flags: int = 0) Tuple[bytes, Tuple]¶
Nhận dữ liệu từ socket. Giá trị trả về là một cặp (bytes, address) trong đó bytes là đối tượng bytes đại diện cho dữ liệu đã nhận và address là địa chỉ của socket đang gửi dữ liệu.
Xem hàm
recv()để giải thích về đối số flags tùy chọn.
- setsockopt(level: int, optname: int, value: int | bytes) None¶
Đặt giá trị của tùy chọn socket đã cho. Các hằng số biểu tượng cần thiết được định nghĩa trong mô-đun socket (SO_* v.v.). value có thể là số nguyên hoặc đối tượng giống bytes đại diện cho một bộ đệm.
- settimeout(value: float | None) None¶
Đặt thời gian chờ cho các thao tác socket chặn. Đối số value có thể là một số dấu phẩy động không âm biểu thị giây, hoặc None. Nếu một giá trị khác không được cho, các thao tác socket tiếp theo sẽ gây ra ngoại lệ
OSErrornếu khoảng thời gian chờ đã trôi qua trước khi thao tác hoàn thành. Nếu đưa vào không, socket được đặt ở chế độ không chặn. Nếu đưa vào None, socket được đặt ở chế độ chặn.Một giải pháp thay thế di động và chung là sử dụng đối tượng
select.poll. Điều này cho phép chờ trên nhiều đối tượng cùng một lúc (và không chỉ trên socket, mà trên các đối tượng stream chung hỗ trợ polling). Ví dụ:# 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
Khác biệt so với CPython
CPython gây ra ngoại lệ
socket.timeouttrong trường hợp hết thời gian chờ, đây là lớp con củaOSError. MicroPython gây ra OSError trực tiếp thay thế. Nếu bạn dùngexcept OSError:để bắt ngoại lệ, mã của bạn sẽ hoạt động cả trong MicroPython và CPython.
- setblocking(flag: bool) None¶
Đặt chế độ chặn hoặc không chặn của socket: nếu flag là false, socket được đặt thành không chặn, nếu không thì ở chế độ chặn.
Phương thức này là viết tắt cho một số lệnh gọi
settimeout()nhất định:sock.setblocking(True)tương đương vớisock.settimeout(None)sock.setblocking(False)tương đương vớisock.settimeout(0)
- makefile(mode: str = 'rb', buffering: int = 0, /) Any¶
Trả về một đối tượng file được liên kết với socket. Kiểu trả về chính xác phụ thuộc vào các đối số được truyền cho makefile(). Hỗ trợ bị giới hạn chỉ ở các chế độ nhị phân ('rb', 'wb', và 'rwb'). Các đối số CPython: encoding, errors và newline không được hỗ trợ.
Khác biệt so với CPython
Vì MicroPython không hỗ trợ các luồng có bộ đệm, các giá trị của tham số buffering bị bỏ qua và được coi như là 0 (không có bộ đệm).
Khác biệt so với CPython
Đóng đối tượng file được trả về bởi makefile() SẼ đóng socket gốc cùng với nó.
- read(size: int | None = None) bytes¶
Đọc tối đa size byte từ socket. Trả về đối tượng bytes. Nếu size không được cho, nó đọc tất cả dữ liệu có sẵn từ socket cho đến EOF; như vậy phương thức sẽ không trả về cho đến khi socket bị đóng. Hàm này cố gắng đọc nhiều dữ liệu nhất có thể (không có "đọc ngắn"). Tuy nhiên điều này có thể không thực hiện được với socket không chặn, và khi đó sẽ trả về ít dữ liệu hơn.