4

TCPソケットを介した接続をリッスンするトランザクションサーバーであるJava(1.6)でサーバーアプリケーションを開発しています。新しい接続ごとに、接続が閉じられるまで存続する新しいスレッドが作成されます。各クライアントは、処理されるトランザクションをサーバーに送信し、応答がクライアントに返されます。

これはうまくいきます。同じソケットを介して多くの非同期トランザクション (またはメッセージ) を送信したい場合に問題が発生します。各トランザクション間に 10 ミリ秒の間隔で 1000 トランザクションを送信する小さなアプリケーションを作成しました。アプリケーションは非同期であるため、メッセージが送信され、応答が途中で返されます。

これは、着信メッセージを処理し、別のコンポーネントに送信して処理する部分のコードです (このコンポーネントにはスレッド プールがあります)。

public void run() {
...
...

  socketBuf = new BufferedInputStream(input);
  baos = new ByteArrayOutputStream();

  while ((bytes_read = socketBuf.read(buffer)) != -1) {

    if (bytes_read < 0) {
        log.error("Tried to read from socket, read() returned < 0,  Closing socket.");
        return;
    }

    baos.write(buffer, 0, bytes_read);
    break;
  }

  if (bytes_read >= 0) {

    baos.flush();
    byte data[] = baos.toByteArray();

    if (data.length > 0) {                      
        GWTranData tData = posMessage.decode(data, false);   
        if (tData.getMessageType() > 0) {

            // Send to the Pre-Online Manager to be processed                       
            PreOnlineJob newJob = new PreOnlineJob(tData);
            newJob.addJobStatusListener(this);
            GWServer.getPreOnlineInstance().addJob(newJob);
        }
    }
  }
  else {
    clientSocket.close();
    break;
  }

} while(true);
  } 

短時間に多くのトランザクションを送信するときに直面する問題は、一部のメッセージが失われ、サーバーに到達しないことです。詳細な分析を行うと、メッセージの送信が速すぎると、バッファーに複数のメッセージが存在することがわかりました。そのため、data[] には 2 つ以上のメッセージがありますが、実行されるメッセージは 1 つだけです。送信されるメッセージのサイズは 200 バイトなので、512 のバッファで十分です。

ソケット読み取りを実装した方法に問題はありますか? より良い方法はありますか?

みんなありがとう。

4

2 に答える 2

7

問題は、ソケットから読み取ったバイトを消費する方法にあります。あなたの仮定は、読み取りごとに 1 つの「メッセージ」を受け取ることです。その仮定は間違っています。TCP はアプリケーション メッセージの境界を認識していませんが、バイトストリームを提供するため、一度に複数のメッセージ、メッセージの一部、またはその両方を取得できます。

受信したストリームの未処理部分をバッファリングし、完全なメッセージを取得したかどうかを確認し、完了するまでさらに読み、メッセージを処理し、ループを続行する必要があります。

編集 0:

TCP の上にアプリケーション レベルのプロトコルを設計するには、いくつかの方法があります。

  • 固定長メッセージ (簡単),
  • 区切られたメッセージ ( SOHFIX や\r\nHTTP のように、メッセージの終了/開始を指定するために明示的なバイト シーケンスが必要です)、
  • @Thomas がコメントで提案しているように、長さの前に付けられたメッセージ、
  • 「自己記述型」メッセージ - S 式などのように、解析する必要があります。
  • 多分他の人。
于 2012-08-16T14:53:18.890 に答える
1

到着したメッセージを処理するようにコードを調整する必要があります。現在、Connect to EOS からのストリーム全体を 1 つの巨大なバイト配列に蓄積し、1 つのメッセージのみが含まれているかのように処理しています。これは、メッセージを「失う」という観点から間違っているだけでなく (失うのはあなたです)、時間とスペースを非常に無駄にします。最初のメッセージを処理する前に EOS を待つ必要はありません。メッセージが 1 つになるまでストリームを読み取り、それを処理し、次のメッセージの処理を繰り返し、EOS で終了する方法を理解する必要があります。

于 2012-08-16T23:59:12.593 に答える