JavaソケットAPIの問題に直面しています。現在ゲームに接続しているプレイヤーの数を表示しようとしています。プレーヤーがいつ接続したかを判断するのは簡単です。ただし、ソケットAPIを使用してプレーヤーがいつ切断したかを判断することは不必要に難しいようです。
リモートで切断されたソケットでisConnected()
を呼び出すと、常にtrue
が返されるようです。同様に、リモートで閉じられたソケットでisClosed()
を呼び出すと、常にfalse
が返されるようです。ソケットが閉じられたかどうかを実際に判断するには、データを出力ストリームに書き込み、例外をキャッチする必要があることを読みました。これは、この状況を処理するための本当に不潔な方法のようです。ソケットがいつ閉じられたかを知るために、ネットワークを介してガベージメッセージを常にスパムする必要があります。
他の解決策はありますか?
接続の現在の状態を通知するTCP APIはありません。 isConnected()
およびisClosed()
は、現在の状態を示しますソケットの。同じことではありません。
isConnected()
はyoが接続されているかどうかthis socketを示します。あなたが持っているので、trueを返します。
isClosed()
はyoが閉じられたかどうかを示しますこのソケットあなたが持っているまでfalseを返します。
peerがconnectionを正常に閉じた場合
read()
は-1を返しますreadLine()
はnull
を返しますreadXXX()
は、他のXXXに対してEOFException
をスローします。
書き込みはIOException
:「ピアによる接続リセット」をスローし、最終的にはバッファリングの遅延が発生します。
他の理由で接続が切断された場合、書き込みは最終的に上記のようにIOException
をスローし、読み取りも同じことを行います。
ピアがまだ接続されているが接続を使用していない場合、読み取りタイムアウトを使用できます。
他の場所で読むかもしれないことに反して、ClosedChannelException
はこれを教えてくれません。 [SocketException: socket closed.
もしません] yoがchannel、を閉じて、それを使い続けたということだけを伝えます。言い換えれば、あなたの側のプログラミングエラーです。閉じられていることを示すものではありませんconnection。
Windows Java 7でのいくつかの実験の結果、XPは次の場合にも表示されます。
OP_READ
で選択していますselect()
はゼロより大きい値を返しますSelectionKey
はすでに無効です(key.isValid() == false
)ピアが接続をリセットしたことを意味します。ただし、これはJREバージョンまたはプラットフォームに固有の場合があります。
さまざまなメッセージングプロトコルでは、パケットを非常に大きくする必要がないため、互いにハートビートを維持する(pingパケットを送信し続ける)のが一般的です。プローブメカニズムにより、TCPが一般的に理解する前に切断されたクライアントを検出することができます(TCPタイムアウトははるかに高い)たとえば2〜3回のプローブに対して返信すると、プレーヤーは切断されます。
また、 関連する質問
投稿された他の答えを見ましたが、あなたはあなたのゲームをプレイしているクライアントと対話的であると思うので、別のアプローチを提案するかもしれません(一方、BufferedReaderは間違いなく有効です).
必要な場合は、「登録」の責任をクライアントに委任できます。つまり各ユーザーから受信した最後のメッセージのタイムスタンプを持つ接続ユーザーのコレクションがあります...クライアントがタイムアウトした場合、クライアントの再登録を強制しますが、それは以下の見積もりとアイデアにつながります。
ソケットが閉じられたかどうかを実際に判断するために、データを出力ストリームに書き込み、例外をキャッチする必要があることを読みました。これは、この状況を処理するための本当に不潔な方法のようです。
Javaコードがソケットを閉じ/切断しなかった場合、リモートホストが接続を閉じたことを他にどのように通知しますか?最終的に、try/catchは、ACTUALソケットでイベントをリッスンするポーラーが実行するのとほぼ同じことを実行します。以下を考慮してください。
抽象化された言語の特徴の1つは、あなたがマニューシャから抽象化されていることだと思います。 SqlConnectionのC#(try/finally)でキーワードを使用することを考えてみてください...ビジネスを行うためのコストです... try/catch/finallyは、Socketの使用に受け入れられ、必要なパターンだと思います。
これはtcp接続の性質だと思います。標準では、送信接続がなくなったと判断するまでに、送信に約6分間の無音が必要です。したがって、この問題の正確な解決策を見つけることができるとは思わない。たぶん、より良い方法は、サーバーがユーザー接続が閉じられたと仮定すべきときを推測するための便利なコードを書くことです。
それは私がそれを処理する方法です
while(true) {
if((receiveMessage = receiveRead.readLine()) != null ) {
System.out.println("first message same :"+receiveMessage);
System.out.println(receiveMessage);
}
else if(receiveRead.readLine()==null)
{
System.out.println("Client has disconected: "+sock.isClosed());
System.exit(1);
} }
result.code == nullの場合
@ user207421が言うように、TCP/IPプロトコルアーキテクチャモデルのため、接続の現在の状態を知る方法はありません。そのため、サーバーは接続を閉じる前にユーザーに通知するか、自分で確認する必要があります。
これは、サーバーによってソケットが閉じられたことを知る方法を示す簡単な例です。
sockAdr = new InetSocketAddress(SERVER_HOSTNAME, SERVER_PORT);
socket = new Socket();
timeout = 5000;
socket.connect(sockAdr, timeout);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream());
while ((data = reader.readLine())!=null)
log.e(TAG, "received -> " + data);
log.e(TAG, "Socket closed !");