Beejはをほのめかしている方法、およびAlastairGは言及は、このようなものに動作します:
の同時接続ごとに、あなたは、読み取りますが、未処理のデータのバッファを維持します。 (これはBeejは二倍最大パケット長にサイジング示唆バッファです)。明らかに、バッファが空から始まり:
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()
機能が有効なヘッダーとコマンドバイトをチェックします):だから例えば、プロトコルのために、それは次のようになります。
がどのrecv()
は短い長さを返すことができるので、この種の技術は、必要が終わる - あなたの提案した方法で、あなたのペイロード長は500ですが、次のrecv()
だけあなたに400のバイトを返す場合、何が起こりますか?とにかくソケットが次回読めるようになるまで、これらの400バイトを保存する必要があります。
複数の同時クライアントを処理する場合は、クライアントごとにrecv_buffer
とrecv_len
という単純な値を設定し、クライアントごとの構造体(クライアントのソケット、おそらくはソースアドレス、現在の状態等。)。
出典
2010-12-03 01:29:52
caf
短い読書+1!私は+ sを追加しますが、許可されません。データがパケット境界を越えて分割され、まだ到着していない可能性があります。または、プログラムが信号を受信している可能性があります。 –
カフェ、ありがとう!コードは常に助けになります。 Beejの説明だけでなく、Alastair'sは今よりはるかに意味をなさない。私はこれがスタック上の他の人にも役立つだろうと確信しています。私はrecvのためにこれに非常に似た何かを実装します。 1つの質問は、行に:result = recv(sock、recv_buffer + recv_len、BUF_SIZE - recv_len、0);あなたは正しくループしていませんか?したがって、たとえば、もしBUF_SIZEが1024ならば、1,024バイトのrecvを実行し、1バイトであってもバッファに入っているものを処理しようとしますか?また、処理するコマンドがたくさんある場合、バッファ上のmemmoveのパフォーマンスヒットはどうなりますか? – Jack
@Jack:そうですね、この回の回では、 'recv(); process_buffer(); 'segment(おそらく' select() 'がブロックされます)。 'process_buffer();'は、1バイトしか持たない場合でも呼び出されます。なぜなら、これは完全なメッセージかどうかをすべてのスマートに1つの場所(この場合は 'process_buffer()すぐにドロップアウトし、 'select()'で終わり、より多くのバイトを待っています)。 – caf