1

HTTPS ソケットの仕組みについて質問があります。

モバイル デバイスとサーバー間の双方向通信を実装する必要があります。

ブルートゥースデバイスから生のバイトとしてリクエストを取得していますが、リクエストはチャンクで受信され、同じ方法で応答を待ちます。つまり、デバイスが私にチャンクを送信しているので、それをサーバーに送信する必要があり、サーバーの応答をデバイスに送り返して、2 番目のチャンクを受信する必要があります。

つまり、ソケットを開いて、リクエストチャンクを書き込んで、レスポンスチャンクを読んでいますが、2番目のリクエストチャンクを書き込んでいるときに、ソケットからデータが受信されません。

コードは次のようになります。

if (webSocket == null) {
    SocketFactory factory = SSLSocketFactory.getDefault();
    webSocket = factory.createSocket(DataUtils.stringValueFromByteArray(requestPackage.getHostAddress()),
                                                   DataUtils.intValueFromByteArray(requestPackage.getHostPort()));

}
 webInputStream = webSocket.getInputStream();
 webOutputStream = webSocket.getOutputStream();


 webOutputStream.write(requestPackage.getDataContent(), 0,requestPackage.getDataContent().length);
 webOutputStream.flush();

byte[] byteBuffer = getBytesFromInputStream(webInputStream);

getBytesFromInputStream は次のようになります。

public static byte[] getBytesFromInputStream(InputStream is)
        throws IOException {



    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    byte buf[] = new byte[8192];
    int ret = 0;
    while ((ret = is.read(buf)) != -1) {
        bout.write(buf, 0, ret);
    }

    byte[] bytes = bout.toByteArray();
    return bytes;
}

は要求の開始時に値を取得し、接続は終了してはなりませんwebSocketnull

ここでの問題は、このコードが最初のチャンクに対して機能することですが、データの 2 番目のチャンクでは、が即座に -1 を返すgetButesFromInputStreamため、空の配列を返します。is.read()

誰かが私が何をすべきかを提案したり、私が間違っていることを説明したりできますか?

どんな助けでも大歓迎です。ありがとう、アークデ

4

3 に答える 3

1

受信側アプリケーションが、送信側アプリケーションによって送信された方法と同じチャンクでデータのフラグメントを取得するというのは、TCP でよくある誤解です。TCP が保証するのは順序 (およびエラーがなければ最終的な配信) だけです。これは全体としてストリームとして扱われるべきです。

このために:

  • 0 バイトの読み取りは、ソケットが閉じていることを示しているわけではありません (これもよくある誤解です)。
  • アプリケーションプロトコルは、アプリケーションプロトコルのさまざまなコマンドを処理できるように、読み取りを停止するタイミングを反対側に伝える区切り文字または代替方法を定義する必要があります。

HTTP 1.1 は、ヘッダーの送信時にサイズがわからない場合に、ヘッダーを使用して、要求/応答またはChunked Transfer-EncodingContent-Lengthの本文で読み取る必要があるバイト数を通知します。

HTTP 要求/応答を読み取りたい場合は、それを処理する必要があります: ヘッダーは空白行で終了し、本文の長さは、Content-Lengthまたは取得したさまざまなチャンクによって指定されます。

コンテンツの長さを読み取りたい場合は、これを自分で実装するのは比較的簡単ですが、チャンク転送エンコーディングも処理できるようにしたい場合は、確かにもう少し手間がかかります。全体として、HTTP ライブラリを使用することもできます。HTTP ライブラリがすべてを行います。ニコライが言うようにHttpsURLConnection、良い方法です。これがニーズに合わない場合は、Apache Http Client ライブラリ (Android AFAIK にも付属) を使用できます。

于 2012-10-24T12:41:17.907 に答える
1

実際に HTTPS を使用している場合は、生のソケットを使用しないでくださいHttpsURLConnection。または、プロトコルを理解する同様の HTTP クライアントを使用してください。次に、BT からの次の各チャンクが新しいリクエストとしてサーバーに送信されます。

于 2012-10-24T07:01:00.810 に答える
0

ingetBytesFromInputStreamの while の前に、別の while を追加します。

while (is.available() == -1) {
    Thread.sleep(100); // for instance. less may very well work too.
}

これは、一部のデータが読み取れるようになるまで待機します。(データがサーバーに到達する時間、サーバーが応答する時間、データがユーザーに到達する時間)

編集

何らかの理由で is.available() は 0 を返すようですが、代わりに is.read を使用できます:

while (ret = (is.read(buf)) <= 0) {
    Thread.sleep(100); // for instance. less may very well work too.
}
bout.write(buf, 0, ret);

(追加の書き込みにより、実際に読み取られたデータが失われるのを回避できます。)

アイデアは、サーバーから何らかの応答が受信されるまで待ってから、実際にそれを読み取ることです。

于 2012-10-24T12:04:02.183 に答える