- PR -

socketのタイムアウトについて

投稿者投稿内容
fujiiki
会議室デビュー日: 2003/06/19
投稿数: 4
投稿日時: 2004-01-28 14:14
事情によりJDK1.1.1を使ってTCP/IPのプログラムを
作っています。
socket(remoteAddr,remotePort)
とした場合、接続相手がいない場合などに接続のタイムアウトまでに
時間がかかってしまいます。
JDK1.4ではconnet()に時間指定が出来るメソッドが追加になっていますが、
JDK1.1.1でこの状況を回避する方法を検討しています。
今検討しているのは以下の通りです。
1.DatagramPakcetを使ってポート7に対してECHO要求を発行する。
2.JNIを利用してPingを発行し、接続相手が正常であることを確認して
  socket()を実行する。
1.の場合、相手がECHO要求を無視するような設定の場合、無効になり、
2.の場合、nativeのPingのコードをC/C++で作成するのは避けたいと思っています。

その他よい回避策あれば、ご教授お願いします。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2004-01-29 23:20
fujiikiさん、こんにちは。

socketを実行するスレッドを独立させ、
タイムアウトをシミュレーションしてはいかがでしょうか?

状態遷移モデルと排他制御を組み合わせれば
できるような気がします。
Keisuke
大ベテラン
会議室デビュー日: 2003/10/24
投稿数: 105
投稿日時: 2004-01-30 02:59
引用:

Kissingerさんの書き込み (2004-01-29 23:20) より:
fujiikiさん、こんにちは。

socketを実行するスレッドを独立させ、
タイムアウトをシミュレーションしてはいかがでしょうか?

状態遷移モデルと排他制御を組み合わせれば
できるような気がします。


connect に割り込むのは無理な気がします。
fujiiki
会議室デビュー日: 2003/06/19
投稿数: 4
投稿日時: 2004-01-30 09:43
Kissingerさん、Keisukeさん
回答ありがとうございます。

Kissingerさんがおっしゃっている内容のことを
http://www.javaworld.com/jw-09-1999/jw-09-timeout.html
を参考に行ってみました。
タイムアウトは親スレッド側で検出できるのですが、
実際にsocketを実行している子スレッドがリターンしてこないので
全体の実行時間自体の制御は出来ませんでした。
Keisukeさんが言われている通りです。

この方法はあきらめて、外部コマンドのpingをコールして
接続相手の状態を確認することにしました。
(これでも実行時間に問題があれば、
JNIでpingを実装するしかないと思っています。)


以上です。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-01-30 10:52
もしかしたらできるかも、という仮説です。実際に試していないですが。
JDK1.3のAPIコードを読んでの考えなので、JDK1.1で適用できるかどうかも分かりません --;

Sun JDKのjava.net.PlainSocketImpl(java.net.SocketImplのデフォルト実装)の
nativeメソッドに、socketConnect(),socketBind(),socketSetOption()などのメ
ソッドがあります。どうも、バークレーソケットインターフェイスの単純なラッパに
なっているようです。

jdk1.3以前のjava.net.Socketはpublicコンストラクタ内部でPlainSocketImplを
生成して即PlainSocketImpl#bind()&connect()をコールしてしまっていますが、
ここを避けるコードを書くと、何とかならないでしょうか?

(例)
Socket#setSocketImplFactory()で、カスタムSocketImplFactoryを登録。
カスタムSocketImplFactoryが生成するSocketImplの実装は以下の通り。
・connect()、bind()では、実際のconnect処理、bind処理を行わない。
 初回の送受信時に初めて実行するよう、処理を遅延させる戦略とする。
・socketSetOption()を直接たたけるインターフェイスを作成する。
 これを利用して、SO_TIMEOUTオプションの値設定を実際のconnect
 処理より前に行えるようにする。
・実際のconnect、bind、setSockOpt等の処理は、PlainSocketImplのnative
 メソッドに委譲する。(privateなので、リフレクションで無理やりコール)

これにより、JNIを使用することなく、connectを行う前にSO_TIMEOUTオプション
をsetSockOptできるようになると思います。それがconnectに対して効くのかどう
かは、JVMの実装依存になってしまいますが・・・

[ メッセージ編集済み 編集者: シュン 編集日時 2004-01-30 10:55 ]

[ メッセージ編集済み 編集者: シュン 編集日時 2004-01-30 11:08 ]
fujiiki
会議室デビュー日: 2003/06/19
投稿数: 4
投稿日時: 2004-01-30 14:04
シュンさん ありがとうございます。

JDK1.4で以下の順で実行してみました。(JDK1.1にはconnect()が無いので)
InetSocketAddress endpoint=
  new InetSocketAddress(InetAddress.getByName(server),servPort);
Socket socket=new Socket();
socket.setSoTimeout(100);
socket.connect(endpoint);

結果はsetSoTimeoutで設定した時間ではタイムアウトになりません
でした。
setSoTimeoutはconnectに対しては効かないようです。
(OSはwindows2000です)

Unixのconnect()にもtimeoutの引数はないですね。
JDK1.4のconnectはどうやってタイムアウトを実装しているのか
興味が湧いてきました。
以上です。

シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-01-30 15:40
ソースを呼んでいただければ分かるのですが、JDK1.4のtimout指定なしの
Sokect#connect()は、単にtimeout指定0でのconnect()にリダイレクト
するだけです。ですので、残念ながらそのテストに意味はありません。

JDK1.3とJDK1.4では、PlainSocketImpl#socketConnect()の引数が変更
(タイムアウトが追加)になっていますので、そこを見ない限り実効のある
結論は得られないと思います。

SunのJVM実装の一部は、SCSLで公開されていると思いますので、興味があ
れば入手してみてはいかがでしょうか。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-01-30 16:36
どうも、労多くて功少なしになりそうですね…
Kissingerさんのおっしゃるように、Socketのコンストラクタの呼び出しから
返ってくるまでを計時して、タイムアウトをシミュレートするようなProxyクラス
を、Socketをラップする形で作るのが、よさそうです。

ということで、失礼しました。

スキルアップ/キャリアアップ(JOB@IT)