0

Java 7およびSSLソケットを使用すると、不可解な問題が発生します。

クライアント/サーバーバンドルがあります。どちらも、非常に単純なプロトコルを使用してXMLデータを相互に送信します。各メッセージの最初の4バイトには、常にメッセージ全体の長さが含まれます。つまり、XMLデータの長さに4バイトを加えたものです。

最初に、クライアントはサーバーにグリーティングメッセージを送信します。次に、サーバーはグリーティングを解釈して応答を送信します。次に、クライアント自体がそのメッセージを解釈し、ログイン情報を送信します。サーバーはその情報をチェックし、応答を送り返します。ただし、今回は、サーバーからグリーティング応答を取得する場合とまったく同じ方法を使用しますが、クライアントは何も受信しません。

これは、クライアント側の簡略化された読み取り方法です。

private String readResponse() throws Exception
{
    BufferedInputStream inputBuffer = new BufferedInputStream(sslSocket.getInputStream());

    // Read and interprete the first 4 bytes to get the length of the XML-data
    int messageLength = readMessageLength(inputBuffer) - 4;

    // PROBLEM OCCURS HERE!

    // Read bufferSize bytes from stream
        byte[] byteArray = new byte[messageLength];
    inputBuffer.read(byteArray);

    // Return the XML-data
    return new String(byteArray);
}

そしてここで最初の4バイトから長さを取得するメソッド...

private int readMessageLength(BufferedInputStream in) throws IOException {
    byte[] b = new byte[4];
    in.read(b, 0, 4);

    return (((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | (b[3] & 0xff));
}

2番目の応答をクライアントが読み取る必要がある場合、にinputBufferはゼロのみが含まれます([0, 0, 0, 0, 0, 0, ...])。したがって、を使用してメッセージの長さを計算しようとするとreadMessageLength()、が返されます-4。もちろん、それは例外につながります。

サーバーによって送信されたデータがまだクライアントによって読み取られる準備ができていないことは明らかなようです。したがって、私はいくつかの変更を加えました:

int messageLength;
do {
    messageLength = readMessageLength(inputBuffer) - 4;
} while(messageLength <= 0);

しかし、それもうまくいきませんでした。そして今、不可解な部分が来ます:何が起こるかというと、このループは2回実行されます!現在割り当てられている値messageLengthは、XMLデータの最初の4バイトから取得されます。reading-methodによって返される文字列は、で始まります?xml。ここで、<が欠落しています。

そこで、最初のバイトをマークしてリセットしようとしました。inputBuffer.mark(4);

int messageLength;
do {
    inputBuffer.reset();
    messageLength = readMessageLength(inputBuffer) - 4;
} while(messageLength <= 0);

しかし、それは実際には無限ループです。内容はinputBuffer決して変わらないので、。messageLength以外になることはありません-4

クライアントに送信されたデータが利用可能であることをいつ確認できますか?どうすれば確認できますか?より良いアプローチは何でしょうか?

よろしく、ウォルター

PS available()メソッドは、SSLソケットを使用すると常にゼロを返すように見えるため、役に立ちません。

4

2 に答える 2

4

絶対に、通信チャネルから読み取られるバイト数を常に確認する必要があります。ゼロになることもありますし、ゼロになることもあります。その場合は読み続ける必要があります。ストリームの終わりに達したのは、負の戻り値のみです。

具体的には、in.read(new byte [100])は必ずしも100バイトを読み取るとは限りません。

すべてを取得していることを保証したい場合は、readFullyを使用する必要があります。

于 2012-08-09T13:23:35.550 に答える
1
private int readMessageLength(BufferedInputStream in) throws IOException {
    byte[] b = new byte[4];
    int len = in.read(b, 0, 4);
    while(len<4)
        len += in.read(b, len, 4- len);

    return (((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | (b[3] & 0xff));
}
于 2012-08-09T13:52:27.990 に答える