Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The method that Beej is alluding to, and AlastairG mentions, works something like this:</p> <p>For each concurrent connection, you maintain a buffer of read-but-not-yet-processed data. (This is the buffer that Beej suggests sizing to twice the maximum packet length). Obviously, the buffer starts off empty:</p> <pre><code>unsigned char recv_buffer[BUF_SIZE]; size_t recv_len = 0; </code></pre> <p>Whenever your socket is readable, read into the remaining space in the buffer, then immediately try and process what you have:</p> <pre><code>result = recv(sock, recv_buffer + recv_len, BUF_SIZE - recv_len, 0); if (result &gt; 0) { recv_len += result; process_buffer(recv_buffer, &amp;recv_len); } </code></pre> <p>The <code>process_buffer()</code> will <em>try</em> and process the data in the buffer as a packet. If the buffer doesn't contain a full packet yet, it just returns - otherwise, it processes the data and removes it from the buffer. So for you example protocol, it would look something like:</p> <pre><code>void process_buffer(unsigned char *buffer, size_t *len) { while (*len &gt;= 3) { /* We have at least 3 bytes, so we have the payload length */ unsigned payload_len = buffer[2]; if (*len &lt; 3 + payload_len) { /* Too short - haven't recieved whole payload yet */ break; } /* OK - execute command */ do_command(buffer[0], buffer[1], payload_len, &amp;buffer[3]); /* Now shuffle the remaining data in the buffer back to the start */ *len -= 3 + payload_len; if (*len &gt; 0) memmove(buffer, buffer + 3 + payload_len, *len); } } </code></pre> <p>(The <code>do_command()</code> function would check for a valid header and command byte).</p> <p>This kind of technique ends up being necessary, because <em>any</em> <code>recv()</code> can return a short length - with your proposed method, what happens if your payload length is 500, but the next <code>recv()</code> only returns you 400 bytes? You'll have to save those 400 bytes until the next time the socket becomes readable anyway.</p> <p>When you handle multiple concurrent clients, you simply have one <code>recv_buffer</code> and <code>recv_len</code> per client, and stuff them into a per-client struct (which likely contains other things too - like the client's socket, perhaps their source address, current state etc.).</p>
 

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