Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The network is <em>always</em> unpredictable. TCP makes a lot of this random behavior go away for you. One wonderful thing TCP does: it guarantees that the bytes will arrive in the same order. But! It does <em>not</em> guarantee that they will arrive chopped up in the same way. You simply <em>cannot</em> assume that every send() from one end of the connection will result in exactly one recv() on the far end with exactly the same number of bytes. </p> <p>When you say <code>socket.recv(x)</code>, you're saying 'don't return until you've read x bytes from the socket'. This is called "blocking I/O": you will block (wait) until your request has been filled. If every message in your protocol was exactly 1024 bytes, calling <code>socket.recv(1024)</code> would work great. But it sounds like that's not true. If your messages are a fixed number of bytes, just pass that number in to <code>socket.recv()</code> and you're done.</p> <p>But what if your messages can be of different lengths? The first thing you need to do: stop calling <code>socket.recv()</code> with an explicit number. Changing this:</p> <pre><code>data = self.request.recv(1024) </code></pre> <p>to this:</p> <pre><code>data = self.request.recv() </code></pre> <p>means <code>recv()</code> will always return whenever it gets new data.</p> <p>But now you have a new problem: how do you know when the sender has sent you a complete message? The answer is: you don't. You're going to have to make the length of the message an explicit part of your protocol. Here's the best way: prefix every message with a length, either as a fixed-size integer (converted to network byte order using <code>socket.ntohs()</code> or <code>socket.ntohl()</code> please!) or as a string followed by some delimiter (like '123:'). This second approach often less efficient, but it's easier in Python.</p> <p>Once you've added that to your protocol, you need to change your code to handle <code>recv()</code> returning arbitrary amounts of data at any time. Here's an example of how to do this. I tried writing it as pseudo-code, or with comments to tell you what to do, but it wasn't very clear. So I've written it explicitly using the length prefix as a string of digits terminated by a colon. Here you go:</p> <pre><code>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) &lt; 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 </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload