0

JavaでTCPソケットクライアントサーバープログラムを使用しています。

クライアントから、センコンドごとにバイナリメッセージ(byte []からのバイナリデータ)を数回送信します。

サーバーから、これらのメッセージを同じ順序とサイズで読みたいと思います。

問題は、サーバーが常に同じサイズのメッセージを読み取るとは限らないことです。それらを「グループ化」しているようです。例えば:

クライアントは以下を送信します:12バイト-12バイト-12バイト-12バイト-15バイト-15バイト

サーバーは以下を受信します:12バイト-48バイト-15バイト-15バイト

どうすればこれを防ぐことができますか?

現在、私のコードは次のとおりです。

クライアント:

(initialization)
mySocket = new Socket(direccion, puerto);
mySocket.setTcpNoDelay(true);
BufferedOutputStream os = new BufferedOutputStream( mySocket.getOutputStream() );

(sending)
os.write( bytes );
os.flush();

サーバ

(initialization)
serverSocket = new ServerSocket(12321);
Socket con = serverSocket.accept();
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));

(receiving)
char[] msg = new char[1024];
String mensaje;
int nbytes;
nbytes = reader.read(msg);

グループ化されたメッセージはバイナリメッセージであり、このモジュールはそれらを「理解」できないため、手動でメッセージを分離することはできません。

したがって、質問は次のとおりです。読者がメッセージを個別に受信することをどのように保証できますか?

ありがとう。

4

2 に答える 2

2

メッセージの転送にデータのストリームを使用しています。ストリームは、概念的には単なるバイトのシーケンスであり、メッセージはありません。ストリームをメッセージ/パケットに分割するのは自分で行う必要があります。現在のコードでは、1回の読み取り呼び出しでメッセージの一部を受信し、次の呼び出しで次の部分を受信することもできます。今のところ、あなたのコードは根本的に欠陥があります。

メッセージの開始/終了場所を明確に検出できるメカニズムを導入します。簡単なアプローチは、各パケットの長さを各パケットの最初のバイトにエンコードすることです。次に、受信者は最初に長さを読み取ることができ、その後、次のバイトのうちのいくつがそのパケットに属しているかを認識します。

別のアプローチは、現在のパケットの終わりを示すメッセージ区切り記号を使用することです。バイナリデータを送信しているため、パケットにすべての可能なバイト値が含まれていないか、すべての可能なバイト値を使用しないようにパケットをエンコードする必要があります。

長さを使用したアプローチは実装がはるかに簡単ですが、終了シンボルアプローチは、新しいシンボルを簡単に導入できるスキーム(たとえば、パケット全体がハフマンエンコードされている場合)に役立ちます。

于 2012-09-14T15:53:22.670 に答える
1

ストリームを転送するのはTCP接続の性質です。

あなたのオプションは

  1. すべてのメッセージの前に長さフィールドを追加するなどして、メッセージを手動で区切ります。これには、プロトコルを変更する必要があります。

  2. TCPとは異なるプロトコルを使用してください。UDP(ただし信頼性が失われます)またはSTCP(Javaがこれに対応できるかどうかはわかりません)のいずれかです。

于 2012-09-14T15:13:02.143 に答える