Điều gì xảy ra nếu bạn không đóng Python?

Ổ cắm được sử dụng gần như ở khắp mọi nơi, nhưng là một trong những công nghệ bị hiểu lầm nghiêm trọng nhất xung quanh. Đây là tổng quan 10.000 foot về ổ cắm. Nó không thực sự là một hướng dẫn - bạn sẽ vẫn còn nhiều việc phải làm để vận hành mọi thứ. Nó không đề cập đến những điểm tốt [và có rất nhiều điểm], nhưng tôi hy vọng nó sẽ cung cấp cho bạn đủ thông tin cơ bản để bắt đầu sử dụng chúng một cách tử tế

ổ cắm

Tôi sẽ chỉ nói về INET [tôi. e. IPv4], nhưng chúng chiếm ít nhất 99% số ổ cắm đang sử dụng. Và tôi sẽ chỉ nói về STREAM [tôi. e. TCP] - trừ khi bạn thực sự biết mình đang làm gì [trong trường hợp này, HOWTO này không dành cho bạn. ], bạn sẽ nhận được hành vi và hiệu suất tốt hơn từ ổ cắm STREAM hơn bất kỳ thứ gì khác. Tôi sẽ cố gắng làm sáng tỏ bí ẩn về ổ cắm là gì, cũng như một số gợi ý về cách làm việc với ổ cắm chặn và không chặn. Nhưng tôi sẽ bắt đầu bằng cách nói về việc chặn ổ cắm. Bạn sẽ cần biết cách chúng hoạt động trước khi xử lý ổ cắm không chặn

Một phần của rắc rối khi hiểu những điều này là “ổ cắm” có thể có nghĩa là một số thứ khác nhau một cách tinh tế, tùy thuộc vào ngữ cảnh. Vì vậy, trước tiên, hãy phân biệt giữa ổ cắm “máy khách” - điểm cuối của cuộc trò chuyện và ổ cắm “máy chủ”, giống như một nhà điều hành tổng đài. Ứng dụng khách [ví dụ: trình duyệt của bạn] chỉ sử dụng ổ cắm “máy khách”;

Lịch sử

Trong số các dạng khác nhau của IPC, ổ cắm cho đến nay là phổ biến nhất. Trên bất kỳ nền tảng nhất định nào, có thể có các dạng IPC khác nhanh hơn, nhưng đối với giao tiếp đa nền tảng, ổ cắm là trò chơi duy nhất trong thị trấn

Chúng được phát minh ở Berkeley như một phần của hương vị BSD của Unix. Chúng lan nhanh như cháy rừng với internet. Với lý do chính đáng — sự kết hợp giữa các ổ cắm với INET giúp việc nói chuyện với các máy tùy ý trên khắp thế giới trở nên dễ dàng đến khó tin [ít nhất là so với các chương trình khác]

Tạo một ổ cắm

Nói một cách đại khái, khi bạn nhấp vào liên kết đưa bạn đến trang này, trình duyệt của bạn đã thực hiện thao tác như sau

# create an INET, STREAMing socket
s = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# now connect to the web server on port 80 - the normal http port
s.connect[["www.python.org", 80]]

Khi connect hoàn thành, ổ cắm s có thể được sử dụng để gửi yêu cầu về văn bản của trang. Ổ cắm tương tự sẽ đọc câu trả lời và sau đó bị hủy. Đúng vậy, bị phá hủy. Ổ cắm máy khách thường chỉ được sử dụng cho một trao đổi [hoặc một nhóm nhỏ trao đổi tuần tự]

Điều gì xảy ra trong máy chủ web phức tạp hơn một chút. Đầu tiên, máy chủ web tạo một “ổ cắm máy chủ”

# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]

Một vài điều cần chú ý. chúng tôi đã sử dụng socket.gethostname[] để thế giới bên ngoài có thể nhìn thấy ổ cắm. Nếu chúng tôi đã sử dụng s.bind[['localhost', 80]] hoặc s.bind[['127.0.0.1', 80]], chúng tôi sẽ vẫn có một ổ cắm “máy chủ”, nhưng một ổ cắm chỉ hiển thị trong cùng một máy.

# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]
0 chỉ định rằng có thể truy cập ổ cắm theo bất kỳ địa chỉ nào mà máy tình cờ có

Điều thứ hai cần lưu ý. số lượng cổng thấp thường được dành riêng cho các dịch vụ “nổi tiếng” [HTTP, SNMP, v.v.]. Nếu chơi lung tung thì dùng số cao đẹp [4 số]

Cuối cùng, đối số của

# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]
1 nói với thư viện ổ cắm rằng chúng tôi muốn nó xếp hàng 5 yêu cầu kết nối [tối đa bình thường] trước khi từ chối các kết nối bên ngoài. Nếu phần còn lại của mã được viết đúng cách, điều đó sẽ rất nhiều

Bây giờ chúng ta có một ổ cắm “máy chủ”, lắng nghe trên cổng 80, chúng ta có thể vào vòng lặp chính của máy chủ web

while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]

Trên thực tế, có 3 cách chung để vòng lặp này có thể hoạt động - gửi một luồng để xử lý

# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]
2, tạo một quy trình mới để xử lý
# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]
2 hoặc cấu trúc lại ứng dụng này để sử dụng ổ cắm không chặn và ghép kênh giữa ổ cắm “máy chủ” của chúng tôi và bất kỳ
# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]
2 đang hoạt động nào . Thêm về điều đó sau. Điều quan trọng cần hiểu bây giờ là. đây là tất cả những gì một ổ cắm "máy chủ" làm. Nó không gửi bất kỳ dữ liệu nào. Nó không nhận được bất kỳ dữ liệu. Nó chỉ tạo ra các ổ cắm "máy khách". Mỗi
# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]
2 được tạo để đáp ứng với một số ổ cắm “máy khách” khác đang thực hiện
# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]
7 cho máy chủ và cổng mà chúng tôi buộc phải thực hiện. Ngay sau khi chúng tôi tạo ra
# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]
2 đó, chúng tôi quay lại lắng nghe để tìm thêm kết nối. Hai "khách hàng" có thể tự do trò chuyện - họ đang sử dụng một số cổng được phân bổ động sẽ được sử dụng lại khi cuộc trò chuyện kết thúc

IPC

Nếu bạn cần IPC nhanh giữa hai quy trình trên một máy, bạn nên xem xét các đường ống hoặc bộ nhớ dùng chung. Nếu bạn quyết định sử dụng ổ cắm AF_INET, hãy liên kết ổ cắm “máy chủ” với

# create an INET, STREAMing socket
serversocket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
# bind the socket to a public host, and a well-known port
serversocket.bind[[socket.gethostname[], 80]]
# become a server socket
serversocket.listen[5]
9. Trên hầu hết các nền tảng, điều này sẽ có một phím tắt xung quanh một vài lớp mã mạng và nhanh hơn một chút

Xem thêm

Tích hợp IPC đa nền tảng vào API cấp cao hơn

Sử dụng ổ cắm

Điều đầu tiên cần lưu ý là ổ cắm “máy khách” của trình duyệt web và ổ cắm “máy khách” của máy chủ web giống hệt nhau. Đó là, đây là một cuộc trò chuyện “ngang hàng”. Hay nói cách khác, với tư cách là nhà thiết kế, bạn sẽ phải quyết định những quy tắc ứng xử trong một cuộc trò chuyện. Thông thường, ổ cắm connecting bắt đầu cuộc trò chuyện, bằng cách gửi yêu cầu hoặc có thể là đăng nhập. Nhưng đó là một quyết định thiết kế - nó không phải là quy tắc của ổ cắm

Bây giờ có hai bộ động từ để sử dụng trong giao tiếp. Bạn có thể sử dụng

while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
2 và
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
3 hoặc bạn có thể biến ổ cắm máy khách của mình thành một con thú giống như tệp và sử dụng
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
4 và
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
5. Cái sau là cách Java trình bày các ổ cắm của nó. Tôi sẽ không nói về nó ở đây, ngoại trừ việc cảnh báo bạn rằng bạn cần sử dụng
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
6 trên ổ cắm. Đây là những "tệp" được lưu vào bộ đệm và một lỗi phổ biến là
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
5 nội dung nào đó, sau đó
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
4 để trả lời. Nếu không có
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
6 trong đó, bạn có thể đợi mãi để nhận được câu trả lời, vì yêu cầu có thể vẫn nằm trong bộ đệm đầu ra của bạn

Bây giờ chúng ta đến với trở ngại chính của ổ cắm -

while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
2 và
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
3 hoạt động trên bộ đệm mạng. Họ không nhất thiết phải xử lý tất cả các byte mà bạn giao cho họ [hoặc mong đợi từ họ], bởi vì trọng tâm chính của họ là xử lý bộ đệm mạng. Nói chung, chúng quay trở lại khi bộ đệm mạng được liên kết đã được lấp đầy [
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
2] hoặc được làm trống [
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
3]. Sau đó, họ cho bạn biết họ đã xử lý bao nhiêu byte. Bạn có trách nhiệm gọi lại cho họ cho đến khi tin nhắn của bạn được xử lý hoàn toàn

Khi một

while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
3 trả về 0 byte, điều đó có nghĩa là phía bên kia đã đóng [hoặc đang trong quá trình đóng] kết nối. Bạn sẽ không nhận được thêm bất kỳ dữ liệu nào trên kết nối này. Không bao giờ. Bạn có thể gửi dữ liệu thành công;

Một giao thức như HTTP chỉ sử dụng một ổ cắm cho một lần truyền. Máy khách gửi yêu cầu, sau đó đọc phản hồi. Đó là nó. Ổ cắm bị loại bỏ. Điều này có nghĩa là máy khách có thể phát hiện phần cuối của câu trả lời bằng cách nhận 0 byte

Nhưng nếu bạn định sử dụng lại ổ cắm của mình để chuyển tiếp, bạn cần nhận ra rằng không có EOT trên ổ cắm. tôi lặp lại. nếu ổ cắm

while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
2 hoặc
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
3 trả về sau khi xử lý 0 byte, kết nối đã bị hỏng. Nếu kết nối không bị ngắt, bạn có thể đợi mãi mãi trên
while True:
    # accept connections from outside
    [clientsocket, address] = serversocket.accept[]
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread[clientsocket]
    ct.run[]
3, vì ổ cắm sẽ không cho bạn biết rằng không còn gì để đọc [hiện tại]. Bây giờ nếu bạn nghĩ về điều đó một chút, bạn sẽ nhận ra một sự thật cơ bản về ổ cắm. tin nhắn phải có độ dài cố định [yuck] hoặc được phân tách [nhún vai] hoặc cho biết thời lượng của chúng [tốt hơn nhiều] hoặc kết thúc bằng cách tắt kết nối. Sự lựa chọn hoàn toàn là của bạn, [nhưng một số cách đúng hơn những cách khác]

Giả sử bạn không muốn kết thúc kết nối, giải pháp đơn giản nhất là một tin nhắn có độ dài cố định

class MySocket:
    """demonstration class only
      - coded for clarity, not efficiency
    """

    def __init__[self, sock=None]:
        if sock is None:
            self.sock = socket.socket[
                            socket.AF_INET, socket.SOCK_STREAM]
        else:
            self.sock = sock

    def connect[self, host, port]:
        self.sock.connect[[host, port]]

    def mysend[self, msg]:
        totalsent = 0
        while totalsent 

Chủ Đề