• 締切済み

TCP通信の切断の検出について

現在javaでTCP通信でサーバーに接続するタイプの大富豪を製作しております。 そこでTCP接続の切断の検出についてお聞きしたいです。 例えば既にあるオンラインのテーブルゲームなどをプレイしていると、誰かの通信が不安定になるor切断された場合、20~30秒程画面の間、動きが止まり、切断されたプレイヤー以外とのチャット等は可能で20~30秒後に誰かが「落ち」てプレイが続行されます。 この時、バックグラウンドではどのような処理が行われているのでしょうか? (1)TCP接続でデータの送信(受信)を行っているがとあるユーザーは切断されているのでそこが何度も送信(受信)のリトライ→反応なし(ACKを受信できず)→タイムアウトが20~30秒に指定してあり、時間経過後にタイムアウトが呼び出され切断されて続行される。 (2)通信が不安定なユーザーが居て切断/接続を何度も繰り返している。プログラム的に20~30秒不安定な状況が続けば切断するようなプログラムを組んでいる。 (3)その他 また、接続の切断の検出はサーバープログラムのどこで行われるのでしょうか。 (1)各接続クラスのInputStream.readもしくはOutputStream.write (2)Socket接続が切断されればどこかで例外が発生する? (3)その他 詳しい方居られましたら教えて頂けると幸いです。

  • Java
  • 回答数3
  • ありがとう数6

みんなの回答

  • Lchan0211
  • ベストアンサー率64% (239/371)
回答No.3

> 現在LAN内でテストをしており、例えばA,Bが接続している状態でAがゲームを終了させると、終了させた瞬間にサーバーがAからの接続の切断を検知します Aがゲームを終了させた場合は、Aの終了時に自動的にFINパケットが送信されるため、 サーバに切断がすぐに伝わります。 > あるオンラインゲーム等をプレイしていると20~30秒ぐらいのフリーズ状態が発生してからユーザーの切断→プレイ再開されます。 これは、どちらかが通信の終了を意図したデータを送信したわけではなく、 データやACKがお互い届かず、何度か再送しているためです。 結局、何度再送しても届かず、タイムアウトにより相手が落ちたことを 認識することになります。 > 一瞬で切断を検知するのはLAN内だからで実際にネット上で実験すると同じような動作をするものなのでしょうか? LAN内かネット上かは、この場合関係ありません。 一瞬で切断を検知したのは、切断パケット(FINやRST)のやりとりがあったためです。 本当の障害はパケットが通らなくなりますから、タイムアウトで検知することになります。 例えば、HUBを介してサーバとクライアントでコネクションを確立している状態で、 クライアントに接続しているLANケーブルを抜いた場合、 クライアント側はケーブルが抜けたことをOSが検知できるので、 クライアント側のsend/recvは、すぐにエラーが帰ります。 一方、サーバはHUBの向こうの通信相手のケーブルが抜けているかどうかは わかりません。サーバがHUBに向けてパケットを送信した場合、 HUBに接続されている宛先PCのケーブルが抜けていたら、 そのパケットは行き場がなく捨てられるだけです。 このためサーバ側はタイムアウトになるまで障害検出できません。

  • askaaska
  • ベストアンサー率35% (1455/4149)
回答No.2

> それでは例えば「プレイヤーがプレイ中にLANケーブルを抜いた」場合は 処理のどのタイミングで抜いたかによるわよ。 最初に接続するときに抜いたなら相手が見つからないかもしれないわね。 Stream中なら書き込み先がなくなっちゃうわね。 テストケースを作成するときは、 「プレイヤーがプレイ中にLANケーブルを抜いた」 をどの処理のタイミングで行うかを考慮しないと ケース漏れになるので注意よ。 もっとも一瞬で終わる処理でどうやるかは困難だけど。 何度も繰り返すしかないわね。 > モバイル 同じ机に置かれている別の端末だろうと 対象がモバイルだろうと同じよ。 それがJavaの強みともいえるわね。 逆に特殊なVMを使われると困るけど・・・。 >20~30秒 チャットは別処理されているだけだろうから省くわね。 2~30秒かかるのは、相手が切断された、というのをどのように判断するか、という問題なのよ。 LAN環境にあるとのことなのでいい例を挙げるわ。 同じLANに接続してあるマシンAの共有フォルダをファイル名を指定して実行で ¥¥マシンA¥共有フォルダ でアクセスできるのはいいわね? でもそのマシンAが落ちているときにアクセスしようとすると しばらく返答がないことが経験できるわ。 これと同じなのよ。 どうしてもすばやく判断したい、というなら サーバとクライアントで1秒ごとに通信を行い、 1秒以上通信がなかったらそれは切断とする というような処理を行う必要あるわ。 この1秒というのが曲者。 インターネットだと環境や、ネットワークトラフィックによっては 通信が数秒遅延するなんてことは大いにありえるわ。 そうすると1秒じゃなくて5秒間隔にするとか 1回失敗したらダメにするんじゃなく、なんかリトライするようにするとか ほら、もう2~30秒経っちゃうでしょ?

  • askaaska
  • ベストアンサー率35% (1455/4149)
回答No.1

やってみればすぐわかると思うけど 結論を言えば  どのタイミングでも発生しうる て言えばいいのかしら。 相手側がどの瞬間で切断されるか そのときの処理で例外が発生するわ。 まあ、たいていはSocketクラスの処理や Streamに対してのI/Oだと思うけどね。 処理するべき例外は大きく3つ IOException UnknownHostException SocketException よ。

to_dairi3
質問者

補足

回答ありがとうございます。 それでは例えば「プレイヤーがプレイ中にLANケーブルを抜いた」場合はどこで切断を検出するでしょうか。 また、最終的にはモバイルにも応用したいと考えているのですが、携帯端末の場合だと「電波状況が悪くなる→圏外になる」「電池が切れる」などのケースが考えられます。このような場合は、サーバー側ではどのような検知→処理になるのかも教えて頂けると幸いです。 現在LAN内でテストをしており、例えばA,Bが接続している状態でAがゲームを終了させると、終了させた瞬間にサーバーがAからの接続の切断を検知しますが、上記のように現在あるオンラインゲーム等をプレイしていると20~30秒ぐらいのフリーズ状態が発生してからユーザーの切断→プレイ再開されます。一瞬で切断を検知するのはLAN内だからで実際にネット上で実験すると同じような動作をするものなのでしょうか?それとも20~30秒間 何らかの処理をバックグラウンドで試みており、それを実装しなければならないのでしょうか。

関連するQ&A

  • TCP通信のブロッキングについて

    初めて投稿させて頂きます。 javaでTCP接続での4人で遊ぶ大富豪を作っております。 サーバーを用意し、各ユーザーがサーバーに接続して遊ぶタイプです。 サーバーの構造は次のようになっております。 ・クライアントから接続を受け付ける待機クラス(Server.java)を常時走らせておく ・待機クラスに接続があれば、1ユーザーごとに送受信のスレッド(client.java)を立ち上げる。各ユーザーからのデータはこのクラスが受け取る ・人数が4人集まれば、テーブルスレッド(table.java)を立ち上げる。各ユーザーと接続されているclient.java(*4)がデータを受け取るとここが計算を行う 各ユーザーがサーバーに接続し、データのやり取りをするところまでは成功したのですが、以下の事について色々調べたのですが分からず、教えて頂けると幸いです。 (質問)ユーザーの接続が切断されたときのTCPの動作について 例えばABCDの4人のプレイヤーが居て、A→B→C→Dの順番だとします。今Aが◇3を切ったとします。するとAから「◇3を切った」というデータをサーバー(サーバーが発行したAとの送受信クラス)に送信し、サーバーが受信、それをABCD全員に送信して手番がBに移ります。この時、仮にCが切断されていてABCDにデータを送信したけどCだけデータが届かない、というケースの場合について、全員のデータの整合性を取るために「サーバーが、"Aが◇3を切った送信"に対するACKパケットを全ユーザーから受信したのを確認してから手番をBに移す」という手順を踏みたいのです。 各クライアントとの送受信のスレッドは余計なところは省略すると以下のようになっております。 class client implements Runnable{ (変数宣言) (コンストラクタ) public void run(){ while(true){ try{ ※(1) in.read(b); // inはSocket.getInputStreamの戻り値 (データを受け取ったことで色々な処理) out.write(b); // outはSocket.getOutputStreamの戻り値 out.flush(); ※(2) }catch(Exception e){} } } } Aと接続されているclientクラスのin.readで「◇3を切った」を受信し、色々な処理を行った後、ABCDと接続している各clientクラスのout.writeで「◇3を切った」を送信します。 ここで質問なのですが、接続が途切れているCの場合、out.write(b)の部分ACKパケットを受信するまで何度もリトライをすると思うのですが、プログラムの動作としてはリトライをしながらもout.write(b)以下の処理に進んでしまうのでしょうか?それともACKを受信するまでここでプログラムはブロックされるorタイムアウト等が発生するまでリトライorサーバーが即切断を認識してExceptionに移行する のでしょうか?私の希望としては例えば上記プログラムの※(1)にf=false;(fはboolean)、※(2)にf=trueなどを置いて「全スレッドのf==trueになれば、次の作業をしてもOK」という風に出来ればプログラム的に楽なのですが、接続が途切れているプレイヤーCのスレッドはout.writeの結果に関わらず(リトライされようが)下の命令を実行してしまうのでしょうか?「ACKパケットを受け取ったか否か」を判断したいのですが、プログラムの動作としては パケットを受け取った/受け取ってない で、どのように差が出るのでしょうか。また、out.writeの内容に関わらずプログラム処理が進んでしまう場合、どのようなプログラムが最適でしょうか。 このサンプルの場合だと、Cとの接続クラスはin.readのところで確実にブロックされますが、もしout.writeでブロックされなければACDのプログラムはBを放っておいてどんどん先に進んでしまい、データの整合性が怪しくなってきます。 詳しい方居られましたらお教え頂ければ幸いです。

  • TCP通信

    OS:Win2000、VisualBasic.netで開発しています。 現在TCP通信のプログラムを製造しています。 TCPサーバとTCPクライアントのテストアプリケーションを作成し、接続テストを行っているのですが、 サーバとクライアントの接続、データ送受信の確認はできました。 しかし、一度クライアント側から接続を切断(ソケットを消去)し、 再びソケットを生成してコネクト要求を出しても接続が確立できません。 このときサーバ側はなにも操作していません。 終始接続待機状態にしてあります。 ソースがないと分かりにくいかもしれませんが、 何か思い当たることがある方、アドバイスよろしくお願いします。

  • TCPのタイムアウトについて

    初歩的な質問で申し訳ありませんが、一般のTCP/IPの通信を行っている際の、 TCPのタイムアウト値って、どのくらいの時間なんでしょうか? 色々調べたのですが、結局いい答えが検索できず、接続の特性に合わせて 動的に調整されると言う回答がでました。 一般的な値でいいのですが、どなたか教えて下さい。 また、HTTPで通信を行う場合、TCPとは別にHTTPは、APレベルのタイムアウト値を 持っているのですよね? それは、TCPのタイムアウト値より、長いのですか?又は、短い時間となりますか? 以上よろしくお願いします。

  • TCP通信のプログラム(java)

    javaを使ってTCP通信のプログラムを作りました。 そのプログラムは次のような動作をさせたいですが、途中までしか動作確認がとれません。 1. 送信側で指定したバイト数のデータを送信する。それにかかった時間を計測する。 2. 送信されたバイトデータを受信する。届いたバイト数の確認をするとともに、受信にかかった時間を計測する。 3. 受信側は1.で行った処理と同じようにして、届いたバイト数分のデータを返信する。 4. 3.で送信側に送信されたデータを受信して、受信時間を計測する。届いたバイト数を確認する。 2.までは、正常に動作します。正常な動作とは、 送信側は、指定した数のバイトデータを送信して、それにかかった時間を計る。 受信側は、送信されたデータを受信して、それにかかった時間を計り、届いたバイト数を確認する。ちなみにこの2つの時間はほぼ同じになります。 ここまではできています。 ですが、送信側が受信側で届いたバイト数分のデータを送信し、送信側でそのデータを受信してその時間を測るというコード(//*受信処理*//という行から下)を追加するとうまくいきません。 受信側では、//*受信処理*//という行から下を追加すると、うまくいきません。 送信と受信処理のコードを載せます。 送信側(送信バイト数は入力させます) Socket sock = new Socket(host, port); BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream()); BufferedInputStream in = new BufferedInputStream(sock.getInputStream()); //*送信処理*// // 送信データを送信する。 int count = 0; // write()の回数 System.out.println("<データ送信処理>"); start = System.nanoTime(); // 計測開始時間 for (int i = 0; i < Data; i++) {   try {     out.write(i);     out.flush();     count++;   } catch (IOException e) {     System.err.println((count + 1) + "つ目のバイト:書き込みエラー");   } } stop = System.nanoTime(); // 計測終了時間 System.out.println("送信完了"); System.out.println("送信されたバイト数:" + count); // 送信スループットを計算する。 // 結果を表示する。 //*受信処理*// // 変数を定義する。 long startNs = 0; // 受信前の時間のナノ秒を返す。 long stopNs = 0; byte[] buf = new byte[1000000]; int total = 0, part; // ストリームの終わりに達し,-1が返されるまで受信する。 System.out.println("<データ受信処理>"); startNs = System.nanoTime(); while ((part = in.read(buf, 0, buf.length)) != -1) {   total += part;   System.out.println(part); } stopNs = System.nanoTime(); System.out.println("受信完了"); System.out.println("受信されたバイト数:" + total); // 受信スループットを計算する。 // 結果を表示する。 // 出力ストリーム・ソケットをクローズする。 out.close(); sock.close(); 受信側のコードは補足欄に載せます。このコードだと、 送信側の計測結果は表示されますが、受信側で受信時間や受信速度などが表示されません。 送信側で通信を強制終了すると、その後に受信側は、結果を表示します。 データを片道ではなく往復させて、それらの処理時間を計測したいのです。うまくいかないのでアドバイスを頂きたいです。 このコードのおかしい部分が分かる方はアドバイスをお願いします。 コードが見にくくて意味がわからないかもしれませんが、そうならば、データを往復させてその時間を測るためのアドバイスをお願いします。

    • ベストアンサー
    • Java
  • TCP,UDPの通信プログラム

    TCPを用いた通信とUDPを用いた通信の二つのプログラムを作っています。 質問なんですが、送信元のアドレスを表示するとき getInetAddress() getAddress() の二つがあると思うのですが、この二つにはどのような違いがあるのでしょうか?

  • tcp/ip接続について

    tcp/ip通信で、さほどパフォーマンスを要求されない場合は、接続しっぱなしよりも、都度接続と切断を繰り返した方がいいのでしょうか? つまり、その方が安定しますか? あるいは、あまり差はありませんか? OSはWindows7です。 よろしくお願いいたします。

  • TCPのコネクションを切断する方法

    FTPのように、制御と転送の2つのポートを利用し、送信元リモートホストごとにforkして対応するTCPサーバプログラムを利用しています。 ここで、OS側から、制御ポート(ログイン等)のコネクションは切断しないで、転送ポートのコネクションだけを切断したいと思うのですが、可能でしょうか。 1つのプロセスが、1つのホストとの制御、転送、両方のコネクションを担当するので、プロセスをkillするわけにはいきません。 Macでは、IPNetMonitorというGUIアプリケーションで、TCPコネクションごとの切断ができるので、Linuxでも可能ではないかと思うのですが... 環境は、redhat7.3です。 よろしくお願いします。

  • UDPを使って通信速度測定プログラムを作成

    java eclipse3.5を使って通信のプログラムを作っています。 TCPの通信速度計測プログラムはWebサイトのソースを参考にして、自分で作りました。 次は、UDPの通信速度計測プログラムを作りたいのです。 TCPでは、送信側で送信データを作成して、受信側で時間を測ります。 データの作成方法と、時間の計測方法は次のようにしています。 送信側: for (int i = 0; i < data - 2; i++) { out.write('X'); } out.write('\\'); out.write('s'); out.flush(); int recvMicroSecond = Integer.parseInt(in.readLine()); System.out.println(data + "バイトを送信するのに" + recvMicroSecond + "マイクロ秒かかる。"); System.out.println(); 送信側で作成したデータ:XXXX…XX\\s 受信側では、最初のXを読み込んだ時点で時間の計測を開始し、sを読み込んだら計測時間をストップして、計測時間を測っています。 UDPでも送信側でこのようなデータをバッファに格納して、 受信側でバッファ内の文字を読み込んで時間の計測を行いたいのですが、 どのクラスの、どのメソッドを使ったらよいか分かりません。 どなたか、よい方法を知りませんか?

    • ベストアンサー
    • Java
  • 初めまして。HPUX11iv2サーバを使ってTCP通信のプログラム開発

    初めまして。HPUX11iv2サーバを使ってTCP通信のプログラム開発を行い始めたものです。 selectの挙動について質問があります。 下記のようにselectの戻りが正常の場合にどのソケットが読み取り可能か調べるプログラムで一番したのelseケースは発生するものでしょうか?(タイムアウト以外で何も読み取り可とならないパターン) 私の書いたプログラムでは発生しています。それが自分のバグでそう動いてしまっているのか、そう動くパターンがあるのか調べて判断がつかなかった為、質問させていただきました。もしわかる方いらっしゃいましたら回答を宜しくお願いいたします。 ret = select ( nfds, &readfds, 0, 0, null ); if ( ret > 0 ) {  if ( FDISSET( procfd, &readfds ) ) // UNIXデータグラムソケット  {   // プロセス間メッセージ受信処理  }  else if ( FDISSET( listenfd, &readfds ) ) // Listen用ソケット  {   // accept処理  }  else if ( FDISSET( tcpfd, &readfds ) ) //TCP送受信用ソケット  {   // TCPメッセージ受信処理  }  else  {  } }

  • winsockを使ったTCP及びUDP通信について

    今回winsockを使った通信プログラムを組む事になったのですが、わからない点が多々ありましたので、どなたかご教授頂けると大変ありがたいです。 1. TCP通信において、送信側が"Hoge" "Fuga"と2回sendした際、受信側でrecvすると"Ho" "geFu" "ga"と3回受信する可能性があると認識しているのですが、これは正しいでしょうか? (到着する順序は保証されるが、recvする際に送信側がどのようにsendしたかは考慮されない) 2. UDP通信においては、上記のような現象は起きないと認識しているのですが、これは正しいでしょうか? (UDP通信では、2回sendすれば2回以上はrecvしない。パケットの破棄はあっても、分割はない) 3. もしUDP通信でも上記のような現象が起きる場合、到着順序の保証がされないという観点から、recvした際に"Ho" "ga" "geFu"と受信する事はあり得るのでしょうか? 4. 2が正しい前提での話です。UDP通信では、MTUを超えた場合、自動でパケットが分割されると聞きました。プログラムを組む際、これは意識しないといけないのでしょうか? (MTUが1500Byteの場合、UDPで2000Byteをsendすると、recvで1500,500と2回受信する?) 以上の4点です。 どなたかご存知の方いらっしゃいましたら、是非ご教授ください。

専門家に質問してみよう