Beej がほのめかし、AlastairG が言及している方法は、次のように機能します。
同時接続ごとに、読み取り済みでまだ処理されていないデータのバッファーを維持します。(これは、Beej が最大パケット長の 2 倍のサイジングを提案しているバッファです)。明らかに、バッファは空から始まります:
unsigned char recv_buffer[BUF_SIZE];
size_t recv_len = 0;
ソケットが読み取り可能なときはいつでも、バッファ内の残りのスペースを読み取ってから、すぐに処理を試みます。
result = recv(sock, recv_buffer + recv_len, BUF_SIZE - recv_len, 0);
if (result > 0) {
recv_len += result;
process_buffer(recv_buffer, &recv_len);
}
は、バッファ内のデータをパケットとして処理しようとしprocess_buffer()
ます。バッファに完全なパケットがまだ含まれていない場合は、単に戻ります。それ以外の場合は、データを処理してバッファから削除します。したがって、プロトコルの例では、次のようになります。
void process_buffer(unsigned char *buffer, size_t *len)
{
while (*len >= 3) {
/* We have at least 3 bytes, so we have the payload length */
unsigned payload_len = buffer[2];
if (*len < 3 + payload_len) {
/* Too short - haven't recieved whole payload yet */
break;
}
/* OK - execute command */
do_command(buffer[0], buffer[1], payload_len, &buffer[3]);
/* Now shuffle the remaining data in the buffer back to the start */
*len -= 3 + payload_len;
if (*len > 0)
memmove(buffer, buffer + 3 + payload_len, *len);
}
}
(do_command()
関数は、有効なヘッダーとコマンド バイトをチェックします)。
短い長さを返すことができるため、この種の手法が必要になります。提案された方法では、ペイロードの長さが 500 であるが、次は 400バイトしか返されない場合はどうなりますか? いずれにせよ、次回ソケットが読み取り可能になるまで、これらの 400 バイトを保存する必要があります。recv()
recv()
複数の同時クライアントを処理する場合は、クライアントごとに 1 つだけをrecv_buffer
用意recv_len
し、それらをクライアントごとの構造体に詰め込みます (これには、クライアントのソケット、おそらくソースアドレス、現在の状態など、他のものも含まれている可能性があります)。