3

私の質問は: ソケットの OutputStream のシャットダウンを実行する方法はありますか、それとも nokia のように正しく/完全に実装されていませんか? (J2ME nokia 実装、nokia c6-00 でテスト済み、ストリームを閉じず、エミュレーターでテスト済み、正常に動作)

主な問題は、J2SE サーバー アプリケーションがストリームの末尾情報を取得しないことです。条件 read(buffer) == -1 が真になることはなく、空のストリームから読み取ろうとし、クライアントが強制終了されるまでハングします。これは、サーバー側アプリケーションの非常に非常に醜い回避策で機能します

        Thread.sleep(10);//wait some time for data else you would get stuck........
        while ((count = dataInputStream.read(buffer)) != -1) {
            byteArrayOutputStream.write(buffer, 0, count);
            if (count != BUFFER_SIZE_1024 || dataInputStream.available() == 0) { //the worlds worst condition ever written... but works
                break;
            }
            Thread.sleep(10);//wait for data input to get some data for dataInputStream.available() to return != 0 if client still sends data else you would not read all data......
        }

しかし、この解決策は絶対に受け入れられません (nokia Java コーディングについて何も知らない、何かが足りない、または何らかの nokia-J2ME コーディング標準に似ているので、慣れるか、プラットフォームを変更する必要があります)

データを受信して​​処理した後、サーバーがクライアントに応答を送信するため、データを送信した後にクライアント ソケットを閉じることができません。

次のようになります: J2ME クライアント -> J2SE サーバー (クライアントが出力ストリームのシャットダウンを実行しないため、読み取りでハングアップ) -> J2ME

J2ME クライアントで dataOutputStream を閉じます - 効果なし setSocketOptions (KEEPALIVE、SNDBUF など) - 効果もエラーもありません

ターゲットデバイスで何も動作していないようです

申し訳ありませんが、Java との無意味な戦いの後、私は今少し怒っています。

解決策を探しましたが、うまくいかないようです

クライアントコード:

        SocketConnection socketConnection = (SocketConnection) Connector.open("socket://" + ip + ":" + port);
        int count;
        byte[] buffer = new byte[BUFFER_SIZE_1024];
        // client -> server
        DataOutputStream dataOutputStream = new DataOutputStream(socketConnection.openDataOutputStream());
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        while ((count = byteArrayInputStream.read(buffer)) != -1) {
            dataOutputStream.write(buffer, 0, count);
            dataOutputStream.flush();
        }
        dataOutputStream.close();
        byteArrayInputStream.close();
4

2 に答える 2

2

J2SE では、ソケットを から初期化し、java.nio.channels.SocketChannel妥当なタイムアウトが経過した後にブロックされたスレッドを中断することをお勧めします。

どちら側を修正しようとしているのかわかりませんが、J2ME の場合、唯一のオプションはsocket timeout を設定することです。

編集

実際、クライアント コードを投稿したので、問題がわかりました。何らかの理由で while ループから例外がスローされた場合、出力ストリームは閉じられません。

そのための私の提案された修正は次のとおりです。

    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);

    try
    {
        DataOutputStream dataOutputStream = new DataOutputStream(
                  socketConnection.openDataOutputStream()
                  );
        try
        {
            while ((count = byteArrayInputStream.read(buffer)) != -1) {
                dataOutputStream.write(buffer, 0, count);
                dataOutputStream.flush();
            }
        }
        finally
        {
            dataOutputStream.close();
        }
    }
    finally
    {
        byteArrayInputStream.close();
    }

ByteArrayInputStream を閉じる必要は厳密にはありませんが、コードには変化する習慣があり、いつかその入力ストリームを明示的に閉じる必要があるものになる可能性があることに注意してください。

于 2012-04-27T18:48:36.913 に答える
1

私は同じ効果でコードを試しました-エミュレーターでは魅力のように動作し、デバイスではハングしますが、次のように問題を解決しました:

J2ME クライアントでは、1024 バイトのパケットを送信する前に、その長さと状態 (IsNextまたはIsLast) を J2SE サーバー側でwhile(true)ループして送信しています。私は最初に長さを で読んでreadShortから、 で状態を読んでいますreadByte(短いものに組み合わせる方が良いことはわかっていますが、それが機能するかどうか、そしてその努力が価値があるかどうかはわかりませんでした。これに触れないでください。また、必要に応じて新しい状態を簡単に追加でき、非常に高速に動作します)。

このサーバーが 2 番目のネストされたループに入った後 [ while (dataInputStream.available() < length) {} - ここにタイムアウトを設定する必要がありますが、それについては後で心配します。また、J2ME ではdataInputStream.available()常に 0 (!) が返されるため、J2ME クライアントでは、この場所のfor (int i = 0; i < length... loop読み取りは 1 バイトの読み取りであることに注意してください]

ループが中断されると、while(dataInputStream.available() ...長さのデータ ブロックを読み取っています。状態が である場合はIsLast、ループを中断しwhile(true)ます。完璧に安定して動作します。

アドバイスをありがとう、この情報が誰かに役立つことを願っています

于 2012-04-29T00:32:12.437 に答える