2011-01-03 14 views
0

クライアントアプリケーションからソケットを使用してサーバーアプリケーションに文字列メッセージを送信しています。私は、クライアントから送信するDataOutputStreamと私のサーバーでメッセージを受信するDataInputStreamを使用しています。クライアントから1つの文字列を送信していますが、サーバーに到達すると、いくつかのメッセージに分割されることがあります。これをどうやって処理するのか、これを処理する最良の方法は何ですか?TCPで受信した壊れたメッセージを解析する方法

おそらく受信した壊れたメッセージをそれぞれ読み取って、各文字で区切り文字が1つのメッセージの最後であることを知ることができます。しかし、これを処理するより良い方法はありますか?

答えて

3

TCPには「メッセージ」というものはありません。これはストリーム指向のプロトコルです。もちろん、より低いレベルでは、それは別々のパケットで送信されますが、あなたはそれを制御する方法がなく、見ているものはそれらのパケットと異なる場合があります。特定の瞬間に受信バッファ内で利用可能な分だけ読み取るだけです。あなたはあなたのメッセージを壊れたものとして知覚するかもしれませんが、いくつかのメッセージがひとつにまとまって到着する状況に遭遇することもあります。

メッセージを読むときは、メッセージの終わりを特定するために何らかの区切り記号を使用するか、メッセージの長さのヘッダーを使用する必要があります。単純な文字列を送る場合は、UTF-8としてそれらをエンコードし、ヌルバイトでそれらを終了するとうまくいくはずです。より複雑なものについては、もっと複雑なアプローチが必要です。

+0

これは、 'networking'タグで*一番質問されて答えられた質問でなければなりません。 – caf

0

メッセージの先頭にヘッダーを付けるのですか?送信の長さとチェックサムを持つヘッダーを送信するのは非常に一般的です。この方法で、適切なサイズのバッファを割り当て、データの整合性を確認することができます。

+2

本当にTCPで整合性を確認する必要はありますか?それはパケットレベルで独自のチェックサムを持っています。 –

+0

@Peter TCPチェックサムもインターネット上の拡張転送に失敗する可能性があることはよく知られていますが、http://elf.cs.pub.ro/soa/wiki/_media/lectures/lecture -09-tcp-crc-csum.pdf –

+1

カスタムチェックサムを使用すると、TCPのチェックサムを破ることなく途中でアプリケーションデータを変更するMan-In-The-Middleプロセスを検出するのに役立ちます。 –

0

最初に長さを送信する簡単な例です。注:無効なメッセージの長さとして読み込みがOutOfMemoryExceptionを引き起こす可能性がある場合、長さをチェックすると混乱したり警告されたりする可能性があります。

public static void writeBytes(DataOutput out, byte [] bytes) throws IOException { 
    out.writeInt(bytes.length); 
    out.write(bytes); 
} 

public static byte[] readBytes(DataInput in) throws IOException { 
    int len = in.readInt(); 
    if (len < 0 || len > 1 << 24) throw new StreamCorruptedException("Invalid message length "+len); 
    byte [] bytes = new byte[len]; 
    in.readFully(bytes); 
    return bytes; 
} 
関連する問題