Trouble 6: ネットワーク処理がうまくいきません
<Q6-1>URLConnectionを利用してWebにアクセスしようとしたのですが、例外が発生し、InputStreamを取得することが出来ませんでした。
以下の例外が発生ました。
java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
(略)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream
(HttpURLConnection.java:574)
| <発生環境> |
| OS |
Any |
| JDK |
Any |
| Vender |
Any |
- <A6-1>
- URLConnectionが使用するProxyの設定を行っていない可能性があります。
Proxyを利用してWebにアクセスする場合は、予め以下のシステムプロパティを設定してください。
(ソースで設定する方法)
設定は、System#setProperty(String, String)を使用して行います。設定値はネットワーク管理者にお問い合わせください。
http.proxyHost … HTTP-Proxyサーバのホスト名
http.proxyPort … HTTP-Proxyサーバのポート番号
(コマンド引数として設定する方法)
java -Dhttp.proxyHost=hostname -Dhttp.proxyPort=portnumber ・・・・
なお、FTPまたはHTTPSでProxyサーバを利用する場合は、別途プロパティを設定する必要があります。
詳細はJava(TM) 2 SDK, Standard Edition ドキュメント:ネットワークのプロパティを参照してください。
<Q6-2>サーバプログラムもクライアントプログラムもクラスパス設定はあっているのに、Naming.bind()、Naming.lookup()でSkel/Stubクラスが見つからないことが原因のRemoteExceptionが発生してしまいます。
| <発生環境> |
| OS |
RedHatLinux6.1/6.2 |
| JDK |
JDK1.2/JDK1.3 |
| Vender |
Sun |
- <A6-2>
- サーバプログラムやクライアントプログラムのcodebaseを正しく設定することで解決できます。
rmiregistryにCLASSPATH環境変数で対象のクラスファイルを設定するという回避策もありますが、rmiregistryの環境設定が必要となるため、推奨されません。
また、codebaseを設定した場合はrmiregistryにCLASSPATHを設定してはいけません。
<Q6-3>Socketでreadブロック中にclose()を呼んでも回線が切断されません。
| <発生環境> |
| OS |
Solaris2.5.1 |
| JDK |
JDK1.2.1 |
| Vender |
Sun |
- <A6-3>
- readブロックしているスレッドに、interrupt()してからclose()を呼ぶ事で解決できます。
<Q6-4>リモートメソッド呼び出しにおいて、ローカルで身に覚えのないRuntimeExceptionやOutOfMemoryErrorが発生してしまいます。
しかし、ローカルのプログラムのヒープ使用状況には問題はありませんでした。
| <発生環境> |
| OS |
RedHatLinux6.2 SMP |
| JDK |
JDK1.3 |
| Vender |
Sun |
- <A6-4>
- 原因として、リモートメソッドのサーバ実装でRuntimeExceptionやOutOfMemoryErrorが発生している可能性が高いです。
サーバ実装で発生したNullPointerExceptionはRemoteExceptionにきれいにネストされて届くとは限りません。
<Q6-5>Naming.bind()、Naming.lookup()でNullPointerExceptionが発生してしまいます。
| <発生環境> |
| OS |
RedHatLinux6.1/6.2 Solaris7 |
| JDK |
JDK1.3 |
| Vender |
Sun |
- <A6-5>
- 該当メソッドの引数に渡すURLをrmi://hostname/objNameの形式にすることで解決できます。不完全なURLを引数に渡した場合、MalformedURLExceptionではなくNullPointerExceptionが発生する場合があります。
<Q6-6>Naming.bind()の引数に他のホストをあらわすURLを渡すと、rmiregistryを正しく実行しているのに例外が発生してbind()できません。
| <発生環境> |
| OS |
RedHatLinux6.1/6.2 |
| JDK |
JDK1.2/JDK1.3 |
| Vender |
Sun/IBM(1.3のみ) |
- <A6-6>
- JDKに付属するrmiregistryの仕様です。他ホストのリモートオブジェクトをbind()することはできません。
<Q6-7>InetAddressクラスが、"256.256.256.256"を正常なアドレスと判定してしまいます。
(JDK1.2.2&Windows2000、JDK1.3&RedHatLinux6.2・Windows2000では同様の問題は再現せず)
| <発生環境> |
| OS |
Solaris2.5.1 |
| JDK |
JDK1.2.1 |
| Vender |
Sun |
- <A6-7>
- 判定メソッドを実装することで回避できます。
<Q6-8>JavaIDL同士でのCORBA通信はできますが、JavaIDLとOrbixWeb3.2での通信ができません。
| <発生環境> |
| OS |
Windows2000 |
| JDK |
JDK1.3 |
| Vender |
Sun |
- <A6-8>
- IDLに、typedef宣言が入れ子構造になっていないかどうかを確認して下さい。入れ子になっている場合、OrbixWeb側は例外を投げて終了してしまうため、入れ子構造になっているtypedefを取り除くことで対処できます。
<Q6-9>java.nioを使用していると、ネットワーク切断によってCPU使用率が100%になることがあります。
java.nioを使用して、ネットワークを使用するシステムを構築しています。
そこで、CPU使用率が100%になるという問題が発生しました。
調査した結果、ネットワーク切断と相関関係があるようです。
どのような原因が考えられますか?
| <発生環境> |
| OS |
Windows XP SP2 |
| JDK |
1.4.1_07 |
| Vender |
Sun |
- <A6-9>
- Javaのバグである可能性があります。
システム内に、Selector#select()を使用した無限ループ構造がありませんか?
JDK1.4.1_04以前のバージョンでは、
ネットワーク切断後に数十秒経過すると、選択できるキーがないにもかかわらず、Selector#select()
がブロックされずそのままreturnしてしまう状態になる、という不具合があります。
その結果、ループ中のどこでもブロックされず、処理が繰り返されることになり、
CPU使用率が100%になってしまいます。
根本的な解決策は、このバグが解決したバージョンである、JDK1.4.2_05以降
を使用することです(Solaris、Linuxでは1.4.2_06で解決されています)。
運用上の問題などでバージョンを上げることができない場合、Selector#select()を呼ぶ前
にThread.sleep()を実行する等して100ms程度待つことで、問題の発生を回避することができます。
<Q6-10>pingは通るのに、java.net.InetAddressのisReachable()がfalseになります。
あるホストに対して、java.net.InetAddressのisReachable()がfalseを返しました。
しかし、同じホストに対してのpingは通ります。
java.net.InetAddressのisReachable()は、pingとして使用できると考えていたのですが、どうなっているのでしょうか?
| <発生環境> |
| OS |
Windows XP SP2 |
| JDK |
5.0 Update4 |
| Vender |
Sun |
- <A6-10>
- java.net.InetAddressのisReachable()は、pingそのものではありません。
APIリファレンスによると、一般的な実装では以下のような方法で到達可能かどうかを判定します。
(1)権限が取得できる場合はICMP ECHO REQUEST(ping)を使用
(2)そうでない場合、目的のホストのポート7(Echo)でTCP接続の確立を試行
しかし、Windowsでは常に(2)の方法で判定を行う実装になっています。
従って、Windowsでpingが成功するのにisReachable()がfalseになる場合、ポート7(Echo)への接続に反応がない可能性があります。
その場合、Echoの失敗の原因を取り除く(ファイアーウォールの7番ポートの接続を許可する等)ことにより、解決されます。
※参考
Solaris及びlinuxでは、APIリファレンスの通りに実装されているため、
権限を取得することができない可能性も考えられます。
対処として、root権限で実行しICMPが選択される様にすることが考えられます。
注意:本文書の内容に誤りがあり、またこの文書によって不利益を被っても、
エスエムジー株式会社は一切関知いたしません。