Hướng dẫn python socket clear receive buffer - bộ đệm nhận xóa ổ cắm python

Tôi cần phải làm trống dữ liệu trên ổ cắm [đảm bảo rằng không có gì để nhận]. Thật không may, không có chức năng cho điều này trong mô -đun ổ cắm Python.

Tôi đã thực hiện một cái gì đó theo cách này:

def empty_socket[sock]:
    """remove the data present on the socket"""
    input = [sock]
    while 1:
        inputready, o, e = select.select[input,[],[], 0.0]
        if len[inputready]==0: break
        for s in inputready: s.recv[1]

Bạn nghĩ sao? Có cách nào tốt hơn để làm điều đó không?

Cập nhật: Tôi không muốn thay đổi thời gian chờ ổ cắm. Tại sao tôi thích chọn để đọc.

Cập nhật: Câu hỏi ban đầu là sử dụng thuật ngữ 'tuôn ra'. Có vẻ như 'trống' là một thuật ngữ tốt hơn.

Cập nhật-2010-02-27: Tôi đã nhận thấy một lỗi khi cặp đã đóng. Đầu vào luôn luôn được lấp đầy bởi các ổ cắm. Tôi đã sửa nó bằng cách thêm một số vòng tối đa. Có sửa chữa tốt hơn không?

Author:
Gordon McMillan

trừu tượng

Ổ cắm được sử dụng gần như ở 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 feet của ổ cắm. Nó không thực sự là một hướng dẫn - bạn vẫn còn phải làm việc trong việc hoạt động. Nó không bao gồm các điểm tốt [và có rất nhiều trong số chúng], nhưng tôi hy vọng nó sẽ cung cấp cho bạn đủ nền để bắt đầu sử dụng chúng một cách khá.

Ổ cắm¶

Tôi chỉ nói về ổ cắm Inet [tức là IPv4], nhưng chúng chiếm ít nhất 99% ổ cắm được sử dụng. Và tôi sẽ chỉ nói về luồng luồng [tức là TCP] còn gì nữa không. Tôi sẽ cố gắng làm sáng tỏ bí ẩn về một ổ cắm là gì, cũng như một số gợi ý về cách làm việc với các ổ 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 cần phải biết cách họ làm việc trước khi xử lý các ổ cắm không chặn.

Một phần của rắc rối với việc 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 để một sự khác biệt giữa một ổ cắm ứng dụng khách của máy khách - một điểm cuối của một cuộc trò chuyện và một ổ cắm máy chủ của máy chủ, giống như một toán tử chuyển mạch. Ví dụ, ứng dụng máy khách [ví dụ, trình duyệt của bạn] sử dụng ổ cắm máy khách của máy khách; Máy chủ web mà nó nói chuyện với việc sử dụng cả ổ cắm máy chủ của máy chủ và máy khách của máy khách.

Lịch sử¶

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

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

Tạo ổ cắm

Nói một cách thô bạo, 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 đã làm một cái gì đó 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 kết nối hoàn thành, ổ cắm S có thể được sử dụng để gửi yêu cầu cho văn bản của trang. Cùng một ổ cắm sẽ đọc câu trả lời, và sau đó bị phá hủy. Đúng vậy, bị phá hủy. Các ổ cắm của máy khách thường chỉ được sử dụng cho một trao đổi [hoặc một bộ trao đổi tuần tự nhỏ].connect completes, the socket s can be used to send in a request for the text of the page. The same socket will read the reply, and then be destroyed. That’s right, destroyed. Client sockets are normally only used for one exchange [or a small set of sequential exchanges].

Những 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 ra một ổ cắm máy chủ trên mạng:

# 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 [] để ổ cắm có thể nhìn thấy với thế giới bên ngoài. Nếu chúng tôi đã sử dụng s.bind [['localhost', 80]] hoặc s.bind [['127.0.0.1', 80]] cỗ máy. S.bind [['', 80]] chỉ định rằng ổ cắm có thể truy cập được bởi bất kỳ địa chỉ nào mà máy xảy ra.socket.gethostname[] so that the socket would be visible to the outside world. If we had used s.bind[['localhost', 80]] or s.bind[['127.0.0.1', 80]] we would still have a “server” socket, but one that was only visible within the same machine. s.bind[['', 80]] specifies that the socket is reachable by any address the machine happens to have.

Một điều thứ hai cần lưu ý: Các cổng số thấp thường được dành riêng cho các dịch vụ nổi tiếng của các dịch vụ [HTTP, SNMP, v.v.]. Nếu bạn đang chơi xung quanh, hãy sử dụng một số cao đẹp [4 chữ số].

Cuối cùng, đối số để nghe nói với thư viện ổ cắm rằng chúng tôi muốn nó xếp hàng lên tới 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, thì đó là rất nhiều.listen tells the socket library that we want it to queue up as many as 5 connect requests [the normal max] before refusing outside connections. If the rest of the code is written properly, that should be plenty.

Bây giờ chúng tôi có một ổ cắm máy chủ trên mạng, nghe trên cổng 80, chúng tôi có thể nhậ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 trong đó vòng lặp này có thể hoạt động - gửi một luồng để xử lý khách hàng, tạo một quy trình mới để xử lý ứng dụng khách hoặc tái cấu trúc ứng dụng này để sử dụng ổ cắm không chặn và Mulitplex giữa ổ cắm máy chủ của chúng tôi và bất kỳ máy khách nào hoạt động của chúng tôi và bất kỳ máy khách đang hoạt động nào Sử dụng Chọn. Thêm về điều đó sau. Điều quan trọng cần hiểu bây giờ là đây: Đây là tất cả các máy chủ của máy chủ. Nó không gửi bất kỳ dữ liệu. Nó không nhận được bất kỳ dữ liệu nào. Nó chỉ sản xuất ổ cắm của khách hàng trên mạng. Mỗi máy khách được tạo ra để đáp ứng với một số ứng dụng khách khác của máy khách khác thực hiện kết nối [] với máy chủ và cổng mà chúng tôi ràng buộc. Ngay khi chúng tôi tạo ra máy khách đó, chúng tôi quay lại lắng nghe nhiều kết nối hơn. Hai máy khách của người Viking có thể tự do trò chuyện - họ đang sử dụng một số cổng được phân bổ động sẽ được tái chế khi cuộc trò chuyện kết thúc.clientsocket, create a new process to handle clientsocket, or restructure this app to use non-blocking sockets, and mulitplex between our “server” socket and any active clientsockets using select. More about that later. The important thing to understand now is this: this is all a “server” socket does. It doesn’t send any data. It doesn’t receive any data. It just produces “client” sockets. Each clientsocket is created in response to some other “client” socket doing a connect[] to the host and port we’re bound to. As soon as we’ve created that clientsocket, we go back to listening for more connections. The two “clients” are free to chat it up - they are using some dynamically allocated port which will be recycled when the conversation ends.

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ớ được chia sẻ. 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ủ của máy chủ thành 'Localhost'. Trên hầu hết các nền tảng, điều này sẽ có một lối tắt xung quanh một vài lớp mã mạng và nhanh hơn một chút.'localhost'. On most platforms, this will take a shortcut around a couple of layers of network code and be quite a bit faster.

Xem thêm

Đa xử lý tích hợp IPC đa nền tảng vào API cấp cao hơn.multiprocessing integrates cross-platform IPC into a higher-level API.

Sử dụng ổ cắm

Điều đầu tiên cần lưu ý, là ổ cắm của Trình duyệt web trên mạng và máy chủ web của máy chủ trên máy chủ của máy khách. Đó là, đây là một cuộc trò chuyện ngang hàng của người Viking. Hoặc để đặt nó một cách khác, với tư cách là nhà thiết kế, bạn sẽ phải quyết định các quy tắc nghi thức là gì cho một cuộc trò chuyện. Thông thường, ổ cắm kết nối bắt đầu cuộc trò chuyện, bằng cách gửi yêu cầu hoặc có lẽ là một dấu hiệu. Nhưng đó là một quyết định thiết kế - nó không phải là một quy tắc của ổ cắm.connecting socket starts the conversation, by sending in a request, or perhaps a signon. But that’s a design decision - it’s not a rule of sockets.

Bây giờ có hai bộ động từ để sử dụng để liên lạc. Bạn có thể sử dụng SEND và RECV, hoặc bạn có thể chuyển đổi ổ 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 đọc và ghi. Cái sau là cách Java trình bày ổ cắm của nó. Tôi sẽ không nói về nó ở đây, ngoại trừ để cảnh báo bạn rằng bạn cần sử dụng Flush trên ổ cắm. Đây là những tập tin được đệm, và một sai lầm phổ biến là viết một cái gì đó, và sau đó đọc để trả lời. Nếu không có sự tuôn ra trong đó, bạn có thể đợi mãi mãi để trả lời, vì yêu cầu vẫn có thể nằm trong bộ đệm đầu ra của bạn.send and recv, or you can transform your client socket into a file-like beast and use read and write. The latter is the way Java presents its sockets. I’m not going to talk about it here, except to warn you that you need to use flush on sockets. These are buffered “files”, and a common mistake is to write something, and then read for a reply. Without a flush in there, you may wait forever for the reply, because the request may still be in your output buffer.

Bây giờ chúng tôi đến khối vấp ngã chính của ổ cắm - Gửi và RECV 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 bạn đưa cho họ [hoặc mong đợi từ chúng], bởi vì trọng tâm chính của họ là xử lý các bộ đệm mạng. Nói chung, họ trở lại khi các bộ đệm mạng liên quan đã được điền [gửi] hoặc làm trống [RECV]. 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.send and recv operate on the network buffers. They do not necessarily handle all the bytes you hand them [or expect from them], because their major focus is handling the network buffers. In general, they return when the associated network buffers have been filled [send] or emptied [recv]. They then tell you how many bytes they handled. It is your responsibility to call them again until your message has been completely dealt with.

Khi một RECV 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 dữ liệu về kết nối này. Bao giờ. Bạn có thể gửi dữ liệu thành công; Tôi sẽ nói thêm về điều này sau.recv returns 0 bytes, it means the other side has closed [or is in the process of closing] the connection. You will not receive any more data on this connection. Ever. You may be able to send data successfully; I’ll talk more about this later.

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

Nhưng nếu bạn có kế hoạch 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 nhắc lại: Nếu một ổ cắm gửi hoặc RECV trả về sau khi xử lý 0 byte, kết nối đã bị hỏng. Nếu kết nối chưa bị phá vỡ, bạn có thể chờ đợi một số tiền mãi mãi, bởi vì ổ cắm sẽ không nói với bạn rằng không có gì để đọc thêm [bây giờ]. 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 của ổ cắm: tin nhắn phải được cố định [yuck] hoặc được phân định [nhún vai] hoặc cho biết chúng có bao lâu [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 sáng hơn những cách khác].send or recv returns after handling 0 bytes, the connection has been broken. If the connection has not been broken, you may wait on a recv forever, because the socket will not tell you that there’s nothing more to read [for now]. Now if you think about that a bit, you’ll come to realize a fundamental truth of sockets: messages must either be fixed length [yuck], or be delimited [shrug], or indicate how long they are [much better], or end by shutting down the connection. The choice is entirely yours, [but some ways are righter than others].

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à thông báo độ 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 

Bài Viết Liên Quan

Chủ Đề