9.11. Đối tượng socket¶
Giao diện Python với tầng truyền tải là lớp socket.socket. Một socket đại diện cho một điểm đầu cuối của một cuộc hội thoại mạng -- một địa chỉ, một cổng, và giao thức (UDP hoặc TCP) mà cuộc hội thoại chạy qua. Các chương điều khiển phần cứng đã mở các instance UART để giao tiếp trên dây; phần này mở các instance socket để giao tiếp trên mạng. Hình dạng là như nhau; dịch vụ bên dưới chỉ có khả năng hơn nhiều.
9.11.1. Tạo socket¶
Ba đối số mô tả một socket: họ địa chỉ nào nó nói, loại socket nào nó cung cấp, và giao thức nào nó sử dụng. Các giá trị mặc định bao gồm các trường hợp mà phần còn lại của phần này sử dụng:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # IPv4 TCP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # IPv4 UDP
Hai hằng số mà ứng dụng chọn giữa trong hầu hết mọi trường hợp:
AF_INET-- địa chỉ IPv4 (một IP số cộng với một cổng). Lựa chọn phổ biến nhất.AF_INET6là tương đương IPv6.SOCK_STREAM-- một kết nối TCP, luồng byte đáng tin cậy.SOCK_DGRAMlà tương đương UDP.
Đối số thứ ba (giao thức) được để ở mức không (zero), điều này chọn giá trị mặc định phù hợp dựa trên hai đối số đầu tiên. Tài liệu đầy đủ về hàm tạo có trên socket --- mô-đun socket.
9.11.2. Địa chỉ trên socket¶
Địa chỉ socket là một tuple của (host, port)
("192.168.1.50", 80)
("0.0.0.0", 8000)
Host là địa chỉ IP dưới dạng chuỗi. Cổng là số nguyên 16-bit được đề cập trên Cổng (Ports).
Một số chuỗi host đặc biệt đáng biết:
"0.0.0.0"có nghĩa là "mọi giao diện IPv4 trên thiết bị này". Một server được gán vào địa chỉ này chấp nhận kết nối trên bất kỳ địa chỉ nào camera có."127.0.0.1"là localhost -- lưu lượng đến địa chỉ này không bao giờ rời khỏi thiết bị. Hữu ích để kiểm thử."255.255.255.255"là địa chỉ broadcast cục bộ. UDP datagram được gửi đến nó sẽ đến tất cả thiết bị trên phân đoạn cục bộ.
Tên miền như "example.com" không phải là chuỗi host hợp lệ trong địa chỉ socket. Chúng phải được phân giải thành IP trước; Tên và DNS đề cập đến lệnh gọi getaddrinfo() thực hiện điều đó.
9.11.3. Hai vai trò¶
Vòng đời của một socket phụ thuộc vào phía nào của cuộc hội thoại nó đang ở. Socket client gọi connect() (hoặc, với UDP, chỉ sendto()) để nói chuyện với một server đã biết. Socket server gọi bind() để đăng ký một cổng, sau đó listen() và accept() (với TCP) hoặc recvfrom() (với UDP) để nhận lưu lượng đến.
Cùng một hàm tạo socket được dùng trong cả hai trường hợp; chỉ các phương thức được gọi sau đó là khác nhau. Ba trang tiếp theo đi qua các mô hình thực tế:
UDP sockets -- gửi và nhận datagram.
TCP sockets -- TCP client và server.
Sockets với asyncio -- tất cả những gì ở trên, nhưng bên trong vòng lặp sự kiện
asyncio.
9.11.4. Đóng socket¶
Mỗi socket giữ một phần nhỏ trạng thái hệ điều hành (một đặt chỗ cổng, các bộ đệm, trạng thái TCP của kết nối). Khi ứng dụng hoàn thành với nó, close() giải phóng trạng thái đó. Socket bị quên là một rò rỉ chậm tích lũy dần; trong một vòng lặp mở kết nối, bỏ qua close cuối cùng sẽ làm cạn kiệt nhóm socket khả dụng của camera.
Mô hình sạch nhất là câu lệnh with
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(addr)
s.send(b"GET / HTTP/1.0\r\n\r\n")
...
# socket is closed automatically here, even on error
Socket triển khai giao thức context-manager được đề cập trong tổng quan Python, vì vậy khối with đảm bảo close() được gọi bất kể khối đó thoát bình thường hay bằng cách raise ngoại lệ.
9.11.5. Tài liệu tham khảo socket¶
Trang này và các trang tiếp theo đi qua API ở dạng tường thuật. Để biết tài liệu tham khảo đầy đủ ở cấp độ đối số của mọi phương thức, mọi cờ và mọi hằng số mà module cung cấp, xem socket --- mô-đun socket. Tài liệu tham khảo cũng là nơi cần tìm cho các thao tác ít phổ biến hơn (tùy chọn socket, thành viên nhóm multicast, IPv6 scope ID) mà phần này không đề cập đến.