Hướng dẫn python socket get buffer size - ổ cắm python lấy kích thước bộ đệm

Lưu ý: Như mọi người đã chỉ ra trong các bình luận, gọi recv () không được phép tham số trong Python, và vì vậy câu trả lời này nên bị coi thường.

Câu trả lời ban đầu:


Mạng luôn không thể đoán trước được. TCP làm cho rất nhiều hành vi ngẫu nhiên này biến mất cho bạn. Một điều tuyệt vời mà TCP làm: Nó đảm bảo rằng các byte sẽ đến cùng thứ tự. Nhưng mà! Nó không đảm bảo rằng họ sẽ đến cắt theo cùng một cách. Bạn chỉ đơn giản là không thể cho rằng mỗi gửi () từ một đầu của kết nối sẽ dẫn đến chính xác một recv () ở đầu xa với cùng một số byte.

Khi bạn nói socket.recv(x), bạn đang nói 'Đừng quay lại cho đến khi bạn đọc x byte từ ổ cắm'. Điều này được gọi là "chặn I/O": bạn sẽ chặn (chờ) cho đến khi yêu cầu của bạn được điền. Nếu mọi thông báo trong giao thức của bạn là chính xác 1024 byte, hãy gọi socket.recv(1024) sẽ hoạt động rất tốt. Nhưng có vẻ như điều đó không đúng. Nếu tin nhắn của bạn là một số byte cố định, chỉ cần chuyển số đó vào

data = self.request.recv()
0 và bạn đã hoàn thành.

Nhưng nếu tin nhắn của bạn có thể có độ dài khác nhau thì sao? Điều đầu tiên bạn cần làm: Ngừng gọi

data = self.request.recv()
0 với một số rõ ràng. Thay đổi điều này:

data = self.request.recv(1024)

với điều này:

data = self.request.recv()

Có nghĩa là

data = self.request.recv()
2 sẽ luôn quay lại bất cứ khi nào nó nhận được dữ liệu mới.

Nhưng bây giờ bạn có một vấn đề mới: Làm thế nào để bạn biết khi người gửi đã gửi cho bạn một tin nhắn đầy đủ? Câu trả lời là: bạn không. Bạn sẽ phải biến độ dài của tin nhắn thành một phần rõ ràng trong giao thức của bạn. Đây là cách tốt nhất: Tiền tố mỗi thông báo có độ dài, dưới dạng số nguyên có kích thước cố định (được chuyển đổi thành thứ tự byte mạng bằng cách sử dụng

data = self.request.recv()
3 hoặc
data = self.request.recv()
4 xin vui lòng!) Hoặc như một chuỗi theo sau là một số dấu phân cách (như '123:'). Cách tiếp cận thứ hai này thường kém hiệu quả hơn, nhưng nó dễ dàng hơn ở Python.

Khi bạn đã thêm nó vào giao thức của mình, bạn cần thay đổi mã của mình để xử lý

data = self.request.recv()
2 Trả lại lượng dữ liệu tùy ý bất cứ lúc nào. Đây là một ví dụ về cách làm điều này. Tôi đã thử viết nó dưới dạng mã giả, hoặc với các bình luận để cho bạn biết phải làm gì, nhưng nó không rõ ràng lắm. Vì vậy, tôi đã viết nó một cách rõ ràng bằng cách sử dụng tiền tố độ dài làm chuỗi các chữ số bị chấm dứt bởi một dấu hai chấm. Bạn đi đây:

length = None
buffer = ""
while True:
  data += self.request.recv()
  if not data:
    break
  buffer += data
  while True:
    if length is None:
      if ':' not in buffer:
        break
      # remove the length bytes from the front of buffer
      # leave any remaining bytes in the buffer!
      length_str, ignored, buffer = buffer.partition(':')
      length = int(length_str)

    if len(buffer) < length:
      break
    # split off the full message from the remaining bytes
    # leave any remaining bytes in the buffer!
    message = buffer[:length]
    buffer = buffer[length:]
    length = None
    # PROCESS MESSAGE HERE

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 < MSGLEN:
            sent = self.sock.send(msg[totalsent:])
            if sent == 0:
                raise RuntimeError("socket connection broken")
            totalsent = totalsent + sent

    def myreceive(self):
        msg = b''
        while len(msg) < MSGLEN:
            chunk = self.sock.recv(MSGLEN-len(msg))
            if chunk == b'':
                raise RuntimeError("socket connection broken")
            msg = msg + chunk
        return msg

Mã gửi ở đây có thể sử dụng cho hầu hết mọi sơ đồ nhắn tin - trong Python bạn gửi chuỗi và bạn có thể sử dụng Len () để xác định độ dài của nó (ngay cả khi nó đã nhúng \ 0 ký tự). Nó chủ yếu là mã nhận được phức tạp hơn. .len() to determine its length (even if it has embedded \0 characters). It’s mostly the receiving code that gets more complex. (And in C, it’s not much worse, except you can’t use strlen if the message has embedded \0s.)

Tăng cường dễ nhất là làm cho ký tự đầu tiên của tin nhắn thành một chỉ báo loại tin nhắn và có loại xác định độ dài. Bây giờ bạn có hai RECV - người đầu tiên có được (ít nhất) nhân vật đầu tiên đó để bạn có thể tra cứu chiều dài và lần thứ hai trong một vòng lặp để có được phần còn lại. Nếu bạn quyết định đi theo con đường được phân định, bạn sẽ nhận được một số kích thước chunk tùy ý, (4096 hoặc 8192 thường là phù hợp tốt cho kích thước bộ đệm mạng) và quét những gì bạn đã nhận được cho một dấu phân cách.recvs - the first to get (at least) that first character so you can look up the length, and the second in a loop to get the rest. If you decide to go the delimited route, you’ll be receiving in some arbitrary chunk size, (4096 or 8192 is frequently a good match for network buffer sizes), and scanning what you’ve received for a delimiter.

Một biến chứng cần biết: Nếu giao thức đàm thoại của bạn cho phép nhiều tin nhắn được gửi lại (không có một loại trả lời nào đó) và bạn chuyển recv một kích thước chunk tùy ý, cuối cùng bạn có thể đọc bắt đầu một tin nhắn sau. Bạn cần phải đặt nó sang một bên và giữ nó, cho đến khi nó cần.recv an arbitrary chunk size, you may end up reading the start of a following message. You’ll need to put that aside and hold onto it, until it’s needed.

Tiền tố tin nhắn với độ dài của nó (giả sử, vì 5 ký tự số) trở nên phức tạp hơn, bởi vì (tin hay không), bạn có thể không nhận được tất cả 5 ký tự trong một RECV. Khi chơi xung quanh, bạn sẽ thoát khỏi nó; Nhưng trong tải mạng cao, mã của bạn sẽ rất nhanh trừ khi bạn sử dụng hai vòng lặp RECV - phần đầu tiên để xác định độ dài, phần thứ hai để lấy phần dữ liệu của tin nhắn. Bẩn thỉu. Đây cũng là khi bạn phát hiện ra rằng Send không phải lúc nào cũng quản lý để loại bỏ mọi thứ trong một lần vượt qua. Và mặc dù đã đọc điều này, cuối cùng bạn sẽ nhận được một chút bởi nó!recv. In playing around, you’ll get away with it; but in high network loads, your code will very quickly break unless you use two recv loops - the first to determine the length, the second to get the data part of the message. Nasty. This is also when you’ll discover that send does not always manage to get rid of everything in one pass. And despite having read this, you will eventually get bit by it!

Trong lợi ích của không gian, xây dựng nhân vật của bạn, (và bảo tồn vị trí cạnh tranh của tôi), những cải tiến này được để lại như một bài tập cho người đọc. Hãy chuyển sang dọn dẹp.

Dữ liệu nhị phân¶

Hoàn toàn có thể gửi dữ liệu nhị phân qua ổ cắm. Vấn đề chính là không phải tất cả các máy đều sử dụng cùng một định dạng cho dữ liệu nhị phân. Ví dụ, một con chip motorola sẽ đại diện cho một số nguyên 16 bit với giá trị 1 là hai byte hex 00 01. Tuy nhiên Các số nguyên 32 bit - NTOHL, HtonL, NTOHS, HTONS trong đó có nghĩa là mạng và có nghĩa là Mạng và có nghĩa là máy chủ, có nghĩa là ngắn và có nghĩa là dài. Trong trường hợp đặt hàng mạng là thứ tự máy chủ, những thứ này không làm gì, nhưng trong đó máy được đảo ngược byte, những thứ này trao đổi các byte xung quanh một cách thích hợp.ntohl, htonl, ntohs, htons where “n” means network and “h” means host, “s” means short and “l” means long. Where network order is host order, these do nothing, but where the machine is byte-reversed, these swap the bytes around appropriately.

Trong những ngày của máy 32 bit, biểu diễn ASCII của dữ liệu nhị phân thường nhỏ hơn so với biểu diễn nhị phân. Đó là bởi vì một lượng đáng ngạc nhiên của thời gian, tất cả các độ dài đó đều có giá trị 0 hoặc có thể là 1. Chuỗi là 0 0 sẽ là hai byte, trong khi nhị phân là bốn. Tất nhiên, điều này không phù hợp với các tin nhắn có độ dài cố định. Quyết định, quyết định.

Ngắt kết nối

Nói đúng ra, bạn có thể sử dụng tắt máy trước khi bạn đóng nó. Việc tắt máy là một lời khuyên cho ổ cắm ở đầu kia. Tùy thuộc vào đối số mà bạn vượt qua nó, điều đó có thể có nghĩa là tôi sẽ không gửi nữa, nhưng tôi vẫn nghe, hay tôi không nghe, câu đố tốt! Tuy nhiên, hầu hết các thư viện ổ cắm đều được sử dụng để các lập trình viên bỏ qua việc sử dụng phần nghi thức này mà thông thường gần giống như Shutdown (); Close (). Vì vậy, trong hầu hết các tình huống, việc tắt máy là không cần thiết.shutdown on a socket before you close it. The shutdown is an advisory to the socket at the other end. Depending on the argument you pass it, it can mean “I’m not going to send anymore, but I’ll still listen”, or “I’m not listening, good riddance!”. Most socket libraries, however, are so used to programmers neglecting to use this piece of etiquette that normally a close is the same as shutdown(); close(). So in most situations, an explicit shutdown is not needed.

Một cách để sử dụng tắt hiệu quả là trong một trao đổi giống như HTTP. Khách hàng gửi một yêu cầu và sau đó tắt máy (1). Điều này cho máy chủ nói với máy khách này đã gửi xong, nhưng vẫn có thể nhận được. Máy chủ có thể phát hiện ra EOF EOF bằng cách nhận 0 byte. Nó có thể cho rằng nó có yêu cầu hoàn chỉnh. Máy chủ gửi trả lời. Nếu việc gửi hoàn thành thành công thì thực tế, khách hàng vẫn nhận được.shutdown effectively is in an HTTP-like exchange. The client sends a request and then does a shutdown(1). This tells the server “This client is done sending, but can still receive.” The server can detect “EOF” by a receive of 0 bytes. It can assume it has the complete request. The server sends a reply. If the send completes successfully then, indeed, the client was still receiving.

Python đưa tự động tắt máy thêm một bước nữa và nói rằng khi một ổ cắm được thu thập, nó sẽ tự động đóng cửa nếu nó cần. Nhưng dựa vào điều này là một thói quen rất xấu. Nếu ổ cắm của bạn biến mất mà không đóng, ổ cắm ở đầu kia có thể treo vô thời hạn, nghĩ rằng bạn chỉ là chậm. Vui lòng đóng ổ cắm của bạn khi bạn hoàn thành.close if it’s needed. But relying on this is a very bad habit. If your socket just disappears without doing a close, the socket at the other end may hang indefinitely, thinking you’re just being slow. Please close your sockets when you’re done.

Khi ổ cắm chết

Có lẽ điều tồi tệ nhất khi sử dụng ổ cắm chặn là những gì xảy ra khi phía bên kia trở nên khó khăn (mà không kết thúc). Ổ cắm của bạn có khả năng treo. TCP là một giao thức đáng tin cậy, và nó sẽ chờ đợi rất lâu trước khi từ bỏ kết nối. Nếu bạn sử dụng các chủ đề, toàn bộ chủ đề về cơ bản đã chết. Có rất nhiều bạn có thể làm về nó. Miễn là bạn không làm một cái gì đó ngu ngốc, như giữ một khóa trong khi thực hiện đọc chặn, chủ đề này thực sự tiêu tốn nhiều theo cách tài nguyên. Đừng cố giết chủ đề - một phần lý do mà các luồng hiệu quả hơn các quy trình là chúng tránh được chi phí liên quan đến việc tái chế tài nguyên tự động. Nói cách khác, nếu bạn quản lý để tiêu diệt sợi chỉ, toàn bộ quá trình của bạn có thể sẽ bị lừa.close). Your socket is likely to hang. TCP is a reliable protocol, and it will wait a long, long time before giving up on a connection. If you’re using threads, the entire thread is essentially dead. There’s not much you can do about it. As long as you aren’t doing something dumb, like holding a lock while doing a blocking read, the thread isn’t really consuming much in the way of resources. Do not try to kill the thread - part of the reason that threads are more efficient than processes is that they avoid the overhead associated with the automatic recycling of resources. In other words, if you do manage to kill the thread, your whole process is likely to be screwed up.

Ổ cắm không chặn

Nếu bạn đã hiểu trước đó, bạn đã biết hầu hết những gì bạn cần biết về cơ chế sử dụng ổ cắm. Bạn vẫn sẽ sử dụng các cuộc gọi tương tự, theo cùng một cách. Nó chỉ là điều đó, nếu bạn làm đúng, ứng dụng của bạn sẽ gần như từ trong ra ngoài.

Trong Python, bạn sử dụng socket.setblocking (0) để làm cho nó không chặn. Trong C, nó phức tạp hơn, (đối với một điều, bạn sẽ cần phải chọn giữa hương vị BSD o_nonblock và hương vị POSIX gần như không thể phân biệt được, hoàn toàn khác với TCP_Nodelay), nhưng đó là một ý tưởng chính xác. Bạn làm điều này sau khi tạo ổ cắm, nhưng trước khi sử dụng nó. (Trên thực tế, nếu bạn là hạt dẻ, bạn có thể chuyển đổi qua lại.)socket.setblocking(0) to make it non-blocking. In C, it’s more complex, (for one thing, you’ll need to choose between the BSD flavor O_NONBLOCK and the almost indistinguishable Posix flavor O_NDELAY, which is completely different from TCP_NODELAY), but it’s the exact same idea. You do this after creating the socket, but before using it. (Actually, if you’re nuts, you can switch back and forth.)

Sự khác biệt cơ học chính là gửi, RECV, kết nối và chấp nhận có thể quay lại mà không làm gì cả. Bạn có (tất nhiên) một số lựa chọn. Bạn có thể kiểm tra mã trả về và mã lỗi và thường khiến bản thân phát điên. Nếu bạn không tin tôi, một lúc nào đó hãy thử. Ứng dụng của bạn sẽ phát triển lớn, lỗi và hút CPU. Vì vậy, hãy để bỏ qua các giải pháp chết não và làm đúng.send, recv, connect and accept can return without having done anything. You have (of course) a number of choices. You can check return code and error codes and generally drive yourself crazy. If you don’t believe me, try it sometime. Your app will grow large, buggy and suck CPU. So let’s skip the brain-dead solutions and do it right.

Sử dụng Chọn.select.

Trong C, chọn mã hóa là khá phức tạp. Trong Python, nó có một miếng bánh, nhưng nó đủ gần với phiên bản C mà nếu bạn hiểu Chọn trong Python, bạn sẽ gặp một chút rắc rối với nó trong C:select is fairly complex. In Python, it’s a piece of cake, but it’s close enough to the C version that if you understand select in Python, you’ll have little trouble with it in C:

ready_to_read, ready_to_write, in_error = \
               select.select(
                  potential_readers,
                  potential_writers,
                  potential_errs,
                  timeout)

Bạn vượt qua chọn ba danh sách: đầu tiên chứa tất cả các ổ cắm mà bạn có thể muốn thử đọc; Thứ hai tất cả các ổ cắm bạn có thể muốn thử viết và lần cuối cùng (thường bị bỏ trống) những ổ cắm mà bạn muốn kiểm tra lỗi. Bạn nên lưu ý rằng một ổ cắm có thể đi vào nhiều hơn một danh sách. Cuộc gọi chọn đang chặn, nhưng bạn có thể cho nó một thời gian chờ. Đây thường là một điều hợp lý để làm - cho nó một thời gian dài tốt đẹp (nói một phút) trừ khi bạn có lý do chính đáng để làm khác.select three lists: the first contains all sockets that you might want to try reading; the second all the sockets you might want to try writing to, and the last (normally left empty) those that you want to check for errors. You should note that a socket can go into more than one list. The select call is blocking, but you can give it a timeout. This is generally a sensible thing to do - give it a nice long timeout (say a minute) unless you have good reason to do otherwise.

Đổi lại, bạn sẽ nhận được ba danh sách. Chúng chứa các ổ cắm thực sự có thể đọc được, có thể ghi và có lỗi. Mỗi danh sách này là một tập hợp con (có thể trống) của danh sách tương ứng bạn đã truyền vào.

Nếu một ổ cắm nằm trong danh sách có thể đọc được đầu ra, bạn có thể gần gũi với chúng ta là một doanh nghiệp mà một số tiền trên ổ cắm đó sẽ trả về một cái gì đó. Ý tưởng tương tự cho danh sách có thể viết. Bạn có thể gửi một cái gì đó. Có thể không phải tất cả những gì bạn muốn, nhưng một cái gì đó tốt hơn là không có gì. .recv on that socket will return something. Same idea for the writable list. You’ll be able to send something. Maybe not all you want to, but something is better than nothing. (Actually, any reasonably healthy socket will return as writable - it just means outbound network buffer space is available.)

Nếu bạn có một ổ cắm máy chủ trên máy chủ, hãy đặt nó vào danh sách tiềm năng_readers. Nếu nó xuất hiện trong danh sách có thể đọc được, bạn sẽ chấp nhận (gần như chắc chắn). Nếu bạn đã tạo một ổ cắm mới để kết nối với người khác, hãy đặt nó vào danh sách tiềm năng_writers. Nếu nó hiển thị trong danh sách có thể viết, bạn có một cơ hội tốt mà nó đã kết nối.accept will (almost certainly) work. If you have created a new socket to connect to someone else, put it in the potential_writers list. If it shows up in the writable list, you have a decent chance that it has connected.

Trên thực tế, chọn có thể tiện dụng ngay cả khi chặn ổ cắm. Nó có một cách để xác định liệu bạn sẽ chặn - ổ cắm có thể đọc được khi có một thứ gì đó trong bộ đệm. Tuy nhiên, điều này vẫn không giúp ích gì cho vấn đề xác định liệu đầu kia được thực hiện, hoặc chỉ bận rộn với một cái gì đó khác.select can be handy even with blocking sockets. It’s one way of determining whether you will block - the socket returns as readable when there’s something in the buffers. However, this still doesn’t help with the problem of determining whether the other end is done, or just busy with something else.

Cảnh báo tính di động: Trên UNIX, chọn hoạt động cả với ổ cắm và tệp. Don lồng thử điều này trên Windows. Trên Windows, chọn chỉ hoạt động với ổ cắm. Cũng lưu ý rằng trong C, nhiều tùy chọn ổ cắm nâng cao hơn được thực hiện khác nhau trên Windows. Trên thực tế, trên Windows, tôi thường sử dụng các chủ đề (hoạt động rất, rất tốt) với ổ cắm của tôi.: On Unix, select works both with the sockets and files. Don’t try this on Windows. On Windows, select works with sockets only. Also note that in C, many of the more advanced socket options are done differently on Windows. In fact, on Windows I usually use threads (which work very, very well) with my sockets.

Kích thước bộ đệm trong ổ cắm là gì?

Kích thước bộ đệm gửi tối đa là 1.048.576 byte. Giá trị mặc định của tùy chọn SO_SNDBUF là 32767. Đối với ổ cắm TCP, độ dài tối đa mà bạn có thể chỉ định là 1 GB.1,048,576 bytes. The default value of the SO_SNDBUF option is 32767. For a TCP socket, the maximum length that you can specify is 1 GB.

AF_Inet trong lập trình ổ cắm là gì?

Gia đình địa chỉ này cung cấp giao tiếp giữa các quá trình giữa các quy trình chạy trên cùng một hệ thống hoặc trên các hệ thống khác nhau.Địa chỉ cho ổ cắm AF_Inet là địa chỉ IP và số cổng.Bạn có thể chỉ định địa chỉ IP cho ổ cắm AF_Inet dưới dạng địa chỉ IP (chẳng hạn như 130,99.provides interprocess communication between processes that run on the same system or on different systems. Addresses for AF_INET sockets are IP addresses and port numbers. You can specify an IP address for an AF_INET socket either as an IP address (such as 130.99.

Setsockopt Python là gì?

Hàm setsockopt () cung cấp một chương trình ứng dụng với các phương tiện để kiểm soát hành vi ổ cắm.Một chương trình ứng dụng có thể sử dụng setsockopt () để phân bổ không gian bộ đệm, thời gian chờ điều khiển hoặc cho phép phát sóng dữ liệu.Tiêu đề xác định các tùy chọn cấp ổ cắm có sẵn cho setsockopt ().provides an application program with the means to control socket behavior. An application program can use setsockopt() to allocate buffer space, control timeouts, or permit socket data broadcasts. The header defines the socket-level options available to setsockopt().

Socket Sock_Stream là gì?

Sock_stream.Cung cấp các luồng byte hai chiều, hai chiều với cơ chế truyền cho dữ liệu luồng.Loại ổ cắm này truyền dữ liệu trên cơ sở đáng tin cậy, theo thứ tự và với các khả năng ngoài băng tần.Trong miền UNIX, loại ổ cắm sock_stream hoạt động giống như một đường ống.Provides sequenced, two-way byte streams with a transmission mechanism for stream data. This socket type transmits data on a reliable basis, in order, and with out-of-band capabilities. In the UNIX domain, the SOCK_STREAM socket type works like a pipe.