7

私はすでにソケットを次のように宣言しています:

serverAddr = InetAddress.getByName(this.ip);
socket = new Socket(serverAddr, port);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);

ただし、次は機能しません。in.ready()常に false を返し、削除するとプログラムはフリーズしますString message = in.readLine();

private void receive() {
        try {
            InputStreamReader isr = new InputStreamReader(socket.getInputStream());
            System.out.println(isr.getEncoding());
            BufferedReader in = new BufferedReader(isr);
            if (in.ready()) {
                String message = in.readLine();
                if (message != null) {
                    if (listener != null) {
                        listener.receiveMessage(ip, message);
                    } else {
                        print("Client recieved: " + message);//
                    }
                }
            }
            in.close();
        } catch (Exception e) {
            print("Error with input stream: " + e);
            disconnect();
        }

    }

どうすればこれを解決できますか?

編集:

これは、私のサーバー クラスで送信がどのように見えるかです: out.println(message); out.flush(); これは、メッセージに何かを入れるたびにループで発生します。このループの後、out は閉じられます。

4

4 に答える 4

4

ready()こんな使い方はいけません。javadocには次のように書かれています。

「戻り値: 次の read() が入力に対してブロックされないことが保証されている場合は true、それ以外の場合は false。 false を返すことは、次の読み取りがブロックされることを保証しないことに注意してください。」

ready() -> falseあなたのコードは、次readがブロックされることを意味すると暗黙的に想定しています。実際には、それは次がブロックread するかもしれないし、しないかもしれないことを意味します。

@EJP が言うように ...read呼び出しを行うだけです。


ブロックを防ぐにはどうすればよいですか?ブロックされている場合、クライアントは何も送信できません

アプリケーションで読み取りのブロックが問題になる場合は、別のスレッドを使用して読み取りを行うか、NIO チャネル セレクターを使用するようにコードを変更してください。

于 2011-05-19T10:58:50.257 に答える
1

私の頭に浮かぶ3つのことがあります:

  • すべてのreceive呼び出しで入力ストリームを再度開き、 BufferedReader. これにより、1 行以上がバッファーに読み込まれる可能性があり、終了 (クローズ) した後、残りのバッファー内のバイトは後続のreceive呼び出しで使用できなくなります。
  • サーバーメッセージを読むために独自のスレッドを使用することを考えましたか? ブロックされても害はありません
  • データの書き込み後にソケットの片側を閉じ、すぐに閉じるときに問題が発生しました。flush()とのclose()呼び出しにもかかわらず、すべてのデータが反対側で受信されない場合がありました。多分これはあなたの状況の問題でもあります

編集:参照をメソッドの外に
置いておくだけでは、問題は完全には解決されません。バッファリングされたすべてのメッセージを読み取るために while ループを使用し、全員に対してリスナーを呼び出す必要があります。次に例を示します。inreceive

if (in.ready()) {
    String message;
    while ((message = in.readLine()) != null) {
        // ...
    }
 }

ただし、最後の行が部分的に読み取られたメッセージである可能性があるので注意してください (たとえば、3 と 1/2 のメッセージがバッファリングされました)。これが問題になる場合は、行がいつ終了するかを判断するためにメッセージを 1 文字ずつ読み、PushbackReader不完全なメッセージを元に戻すために a を使用できます。

于 2011-05-19T11:09:21.253 に答える