7

私は Java の本からネットワーキングを学んでいるので、ちょっと初心者です。この問題は、本やオンラインで見つけることができなかったので、インターネットに問い合わせることにしました。

この本には、ObjectOutputStream と ObjectInputStream を使用して、オブジェクトを異なるコンソールに送受信するように書かれています。

これで、送信したオブジェクトを正常に受信できますが、1 回だけです。ランダムな文字列、整数、名前のないインスタンスなど、さまざまなオブジェクトを送信すると、コンソールにはすべて正しいフィールドが表示されます。しかし、オブジェクトのインスタンスを送信し、インスタンスのフィールドの 1 つの値を変更してオブジェクトを再送信すると、入力ストリームは元のインスタンスの値をロードします。

たとえば、public int "var" が 1 のクラスのインスタンスがあるとします。このクラスのインスタンスを送信すると、クライアントはそれを受信し、var = 1 と正しく報告します。 var を (同じインスタンスで) 2 に変更して再送信すると、クライアントは read() メソッドの呼び出しを終了します (したがって、新しいオブジェクトを受信したに違いありません!) が、var が 1 であると報告されます。インスタンスをまだ受け取っていない別のクライアントは、var を 2 として正しく報告し、var を変更しても 2 として報告し続けます。

クライアントがインスタンスの正しいバージョンを以前に受信していない場合に読み取るという事実は、オブジェクトが出力ストリームを介して適切に送信されていることを意味する必要があります。何らかの理由で入力ストリームが機能していません。同じオブジェクトであることを認識しているように見えるため、チェックせずに同じ値を持っていると想定します。なぜこれが起こり、どうすれば修正できますか?

ばかげたことを聞いていたら申し訳ありませんが、この本ではシリアライゼーションとソケットがどのように機能するかは説明されておらず、それらの使用方法のみが説明されているため、それらの使用方法について根本的に混乱する可能性があります。ありがとうございました!

問題をテストするために私が書いた簡単なコード:

サーバー: (更新されたオブジェクトを送信し続けるためのタイマー アクションがあります)

    public void actionPerformed(ActionEvent e)
{
    object.var++;
            output.write(object);
            output.flush();
            System.out.println(object.var);
}

クライアント

    public void run()
{
    while(true)
            {
                   Test t = (Test)input.readObject();
                   System.out.println(t.var);
            }
    }

これらのプログラムを実行すると、サーバー クラスの出力は 1、2、3、4... と無限に増加しますが、クライアントの出力は 1、1、1、1、1、1、1 などになります。

これを読んでいただきありがとうございます。私がばかげているだけなら申し訳ありませんが、私はこのようなことに慣れていません。

EDIT:申し訳ありませんが、read()はタイプミスでした(フォーマットを正しく取得できなかったため、手動でコードを入力しました)、input.readObject()を意味しました

4

3 に答える 3

17

その理由はObjectOutputStream、同じオブジェクトが 2 回書き込まれると、オブジェクト参照がキャッシュされ、逆参照がストリームに書き込まれるためです。つまりwrite、2 回目にストリームを呼び出すと、実際にはオブジェクトの新しいコピーが書き込まれず、既に書き込まれたオブジェクトへの参照が挿入されるだけです。

ObjectOutputStream.resetwrite の呼び出しの間に呼び出しを行うことで、これを防ぐことができます。これにより、キャッシュされた参照を破棄するようにストリームに指示されます。

この動作は奇妙に思えますが、循環参照を持つオブジェクト グラフをシリアル化しようとする場合 (つまり、オブジェクト A を参照するオブジェクト B を参照するオブジェクト A を記述する場合) は、実際には無限ループを防ぐ必要があります。

于 2011-06-15T03:58:08.167 に答える
3

ObjectInputStreamのread()またはreadObject()を使用していますか?read()を使用している場合は、1バイトのデータを取得しているだけです。クライアントを変換してみてください

public void run()
{
  while(true)
  { 
    Test t = (Test)input.readObject();
    System.out.println(t.var);
  }
}

編集:input.readObject();である必要があります。

于 2011-06-15T03:06:20.993 に答える
-1

このようなコードのデバッグに何時間も費やしてきました。:)

これに対する適切な解決策はわかりませんが、オブジェクトの新しいインスタンスを作成するか、単にclone()すると、送信する前にコードが期待どおりに機能するはずです。

VMは、受信しているオブジェクトを既に持っているオブジェクトとして認識し、実際に変更があるかどうかを確認することなく、クライアントでポインターを更新するだけのようです。

試す...

public void actionPerformed(ActionEvent e)
{
    object.var++;
    //assuming your object supports clone()
    output.write(object.clone());
    output.flush();
    System.out.println(object.var);
}
于 2011-06-15T03:05:19.633 に答える