3

エラーが表示されます:

IOException on socket listen: java.io.NotSerializableException: java.net.Socket

私はこのコードでソケット経由でオブジェクトを送信しようとします:

ObjectOutputStream outObjects = new  ObjectOutputStream(socket.getOutputStream());
outObjects.writeObject(currentPlayer);

output.flush();

2行目でエラーが発生します....しかし、クラスPlayer(currentPlayerオブジェクトのクラス)をシリアル化(Serializableを実装)しましたが、Playerクラスのメンバーの1つはSocketオブジェクトです.....再定義してシリアル化しようとしましたソケットオブジェクトですが、問題を解決する方法はありません....どこが間違っていますか?

4

6 に答える 6

4

Socket オブジェクトをシリアライズできないため、ソケット フィールドを一時的なものにする必要があります。ソケット プロパティの一部が必要な場合は、追加のフィールドを Player に配置して、これらのフィールドを表すことができます。

于 2011-02-04T13:13:41.027 に答える
3

これは、Socket クラスがシリアライズ可能でないことを意味します。

Socket メンバーを一時的に設定する必要があります。その後、シリアル化されません。

プライベート readObject(ObjectInputStream) メソッドで Socket オブジェクトを必ず再作成してください。そうしないと、null ポインター例外が発生する可能性があります。

于 2011-02-04T13:13:10.093 に答える
1

ソケットは、実行中のマシンや OS などに関連付けられているため、シリアル化できません。シリアライズ可能にするには、 object のクラスが Serializable を実装する必要があり、すべて再帰的にシリアライズ可能であるオブジェクトが含まれている必要があります。

したがって、プレーヤーをシリアライズするには、そのソケット属性をシリアライゼーションから除外する必要があります。これを行うには、属性 transient を宣言します。

private transient Socket mySocket;

したがって、プレーヤーが逆シリアル化されると、そのソケットは null になり、正しく動作しない可能性が高くなります。ソケットが機能する必要があるオブジェクトをシリアライズすることはおそらく意味がないため、おそらく設計を見直す必要があります。

于 2011-02-04T13:19:08.257 に答える
1

この問題を解決するにはいくつかの方法がありますが、最速の方法は Socket メンバーをマークすることtransientです。これにより、Java のデフォルトのシリアライゼーションが Socket を無視し、コピーに null が含まれるようになります。

private transient Socket sock;

または、独自のシリアル化メソッドを提供することもできます。これには、すべてのメンバーを自分で書き込んで読み取る必要があります。Serializable (以下を参照)で定義されたメソッドを使用するか、代わりにExternalizableを実装できます。

 private void writeObject(java.io.ObjectOutputStream out)
     throws IOException
 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;

Players の状態をネットワーク コードから分離するのが最もクリーンで、Serializable メンバーのみを持つクラスになります。おまけとして、送信クラスに無効なメンバー フィールドが含まれなくなりました。

于 2011-02-04T13:27:01.833 に答える
1

コメントに答えるために編集されました

transientソケットメンバーを次のように宣言してみてください

private transient Socket socket;

これにより、シリアル化機構が の値を送信しようとするのを抑制しますsocket。ソケットハンドルなどの OS リソースを表す値を保持するオブジェクトを別のプロセスに送信することはできないことに注意してください。最良の場合、受信側でそのようなオブジェクトを使用しようとすると、例外がスローされます。最悪の場合、このような試みによって微妙なバグ (データが間違ったユーザーに送信される) が発生する可能性があります。このため、そのようなオブジェクトはシリアライズできません (誰かがミスをした場合を除く)。

次の (簡略化された) 例を考えてみましょう。UNIX では、ソケットは整数 (いわゆるファイル記述子) で表され、ソケットの作成時に OS によって返されます。この値が別のプロセスに送信された場合、この数値が実際に受信プロセスで開いている有効なファイル ハンドルを参照しているという保証はありません。さらに悪いことに、受信プロセスで同じ数値を持つファイル ハンドルが存在する場合、送信プロセスで開いている同じソケットを参照することはほとんど不可能です。そのため、データを送信するときに受信プロセスで番号が実際にファイル記述子として使用される場合、ほぼ確実に意図した宛先以外の場所に送信されます。

送信プロセスと受信プロセスが同じマシン上にある場合、あるプロセスから別のプロセスに「ソケット」を転送する方法があります。しかし、Java からこれらの OS 呼び出しにアクセスする簡単な方法があるとは思えません。

于 2011-02-04T13:13:56.557 に答える
1

implements Serializableそれ自体ではオブジェクトをシリアライズ可能にしません。オブジェクト自体のシリアル化されたすべてのフィールド (およびオブジェクトに含まれるすべてのフィールド) は、シリアル化可能である必要があります。

ソケットはシリアル化できないため、回線経由で送信しないでください。transientとして宣言することで、シリアル化から除外できます。もちろん、逆シリアル化されたオブジェクトにはソケットがないため、オブジェクト内のオプションの readObject および writeObject メソッドを確認して、シリアル化と逆シリアル化に使用することもできます。

シリアライゼーションに関するこの記事をチェックしてください。

于 2011-02-04T13:16:07.457 に答える