JavaTM RMI によるカスタムソケットファクトリの使用 |
ドキュメントの目次 |
このチュートリアルでは、JavaTM Remote Method Invocation (Java RMI) によってカスタムソケットファクトリを実装して使う手順を説明します。カスタムソケットファクトリは、リモートメソッド呼び出しがネットワークレベルで通信する方法を制御するために使用できます。たとえば、このカスタムソケットファクトリを使用して、ソケットオプションの設定、アドレスのバインドの制御、認証に要求されるような接続の確立の制御、および暗号化や圧縮などのデータのエンコードの制御を行うことができます。
コンストラクタや java.rmi.server.UnicastRemoteObject
または java.rmi.activation.Activatable
の exportObject
メソッドなどでリモートオブジェクトがエクスポートされる場合、カスタムクライアントソケットファクトリ (java.rmi.server.RMIClientSocketFactory
インスタンス) およびカスタムサーバソケットファクトリ (java.rmi.server.RMIServerSocketFactory
インスタンス) を指定して、リモートオブジェクトのリモート呼び出し通信時に使用されるようにすることが可能です。
クライアントのソケットファクトリは、リモート呼び出しを開始するために使用されるソケットの作成を制御し、接続が確立される方法と使用するソケットのタイプを制御するのに使用できます。 サーバのソケットファクトリは、リモート呼び出しを受信するために使用するサーバソケットの作成を制御するため、着信接続の待機および受け入れ方法に加え、着信接続に使用するソケットのタイプの制御にも使用できます。
リモートオブジェクトに対応するリモートスタブには、リモートオブジェクトがエクスポートされるときにあれば、クライアントのソケットファクトリが含まれます。したがって、クライアントのソケットファクトリは直列化が可能であることが必要であり、そのコードは、スタブクラスのコードやリモート呼び出しで渡されるその他の直列化できるオブジェクトと同様に、クライアントがダウンロードすることができます。
また、カスタムソケットファクトリでレジストリをエクスポートするための LocateRegistry.createRegistry
メソッドと、カスタムのクライアントソケットファクトリでレジストリに対応するスタブを取得するための LocateRegistry.getRegistry
メソッドもあります。
(さらに、Java RMI 用のグローバルソケットファクトリもあることに注意してください。これは、java.rmi.server.RMISocketFactory
の setSocketFactory
メソッドで設定できます。このグローバルソケットファクトリは、リモートスタブがカスタムのクライアントソケットファクトリを含んでいないときにソケットを作成する場合、およびリモートオブジェクトがカスタムのサーバソケットファクトリ付きでエクスポートされないときにサーバソケットを作成する場合に使用されます。)
このチュートリアルは次の 3 つの部分に分かれています。
多くのユーザは、相互認証や暗号化などの、Java RMI クライアントとサーバ間の安全な通信に興味を持っています。カスタムソケットファクトリには、このためのフックが用意されています。詳細は、「Java RMI での SSL の使用」を参照してください。このチュートリアルで使われているソースコードは、次のファイル形式から選ぶことができます。
ServerSocket
と Socket
を実装するRMIClientSocketFactory
を実装するRMIServerSocketFactory
を実装するステップ 1:
使用するソケットのタイプは、アプリケーションの仕様によって決まります。サーバが機密データを送信または受信する場合は、データを暗号化するソケットを選びます。
カスタムServerSocket
とSocket
を実装するこの例のカスタムソケットファクトリは、単純な XOR 暗号化および暗号解読を実行するソケットを生成します。この種の暗号化は、暗号解読の知識のある者であれば簡単に解読されますが、ここでは例を単純にするために使用します。
カスタム XOR ソケットの実装には、次のソースが含まれます。XOR ソケットは、特殊な入力と出力のストリーム実装を使用して、ソケットに対して読み書きされるデータの XOR 処理を行います。
ステップ 2:
クライアント側ソケットファクトリ
カスタムRMIClientSocketFactory
を実装するXorClientSocketFactory
は、java.rmi.server.RMIClientSocketFactory
インタフェースを実装します。クライアントソケットファクトリは、createSocket
メソッドを実装して、適切なクライアントソケットインスタンスXorSocket
を返す必要があります。クライアントソケットファクトリは、
java.io.Serializable
インタフェースを実装して、インスタンスがリモートスタブの一部としてクライアントに直列化されるようにする必要があります。さらに、equals
メソッドとhashCode
メソッドを実装して、Java RMI 実装が、同等のクライアントソケットファクトリを使用するリモートスタブのインスタンス間でリソースを正しく共有できるようにすることも必須です。package examples.rmisocfac; import java.io.*; import java.net.*; import java.rmi.server.*; public class XorClientSocketFactory implements RMIClientSocketFactory, Serializable { private byte pattern; public XorClientSocketFactory(byte pattern) { this.pattern = pattern; } public Socket createSocket(String host, int port) throws IOException { return new XorSocket(host, port, pattern); } public int hashCode() { return (int) pattern; } public boolean equals(Object obj) { return (getClass() == obj.getClass() && pattern == ((XorClientSocketFactory) obj).pattern); } }ステップ 3:
サーバ側ソケットファクトリ
カスタムRMIServerSocketFactory
を実装するXorServerSocketFactory
は、java.rmi.server.RMIServerSocketFactory
インタフェースを実装します。サーバソケットファクトリは、createServerSocket
メソッドを実装して、適切なサーバソケットインスタンスXorServerSocket
を返す必要があります。サーバソケットファクトリのインスタンスはリモートスタブ内に含まれていないので、サーバソケットファクトリは
Serializable
インタフェースを実装する必要はありません。equals
メソッドとhashcode
メソッドを実装して、Java RMI 実装が、同等のソケットファクトリでエクスポートされたリモートオブジェクト間でリソースを正しく共有できるようにすることも、引き続き必須です。package examples.rmisocfac; import java.io.*; import java.net.*; import java.rmi.server.*; public class XorServerSocketFactory implements RMIServerSocketFactory { private byte pattern; public XorServerSocketFactory(byte pattern) { this.pattern = pattern; } public ServerSocket createServerSocket(int port) throws IOException { return new XorServerSocket(port, pattern); } public int hashCode() { return (int) pattern; } public boolean equals(Object obj) { return (getClass() == obj.getClass() && pattern == ((XorServerSocketFactory) obj).pattern); } }
RMIClientSocketFactory
および RMIServerSocketFactory
実装を使用するリモートオブジェクトを作成してエクスポートする、サーバアプリケーションを作成する。リモートオブジェクトのスタブへの参照を Java RMI レジストリに保存して、クライアントがそれを検索できるようにする
ステップ 1:
リモートオブジェクトとの通信でカスタムソケットを使用する必要がある場合は、リモートオブジェクトをエクスポートするときに使用するカスタムソケットファクトリを指定する必要があります。カスタムソケットファクトリを指定するリモートオブジェクトがアプリケーションからエクスポートされると、Java RMI ランタイムは、対応するカスタムの
サーバアプリケーションを作成するRMIServerSocketFactory
を使用して、そのリモートオブジェクトへの着信呼び出しを受け入れるためのサーバソケットを作成します。また、対応するカスタムのRMIClientSocketFactory
を含むスタブも作成します。このクライアントソケットファクトリは、そのスタブを使用するリモートオブジェクトへのリモート呼び出しを起動するときに接続を作成するために使用されます。この例は、「Java RMI 入門」チュートリアルの例に似ていますが、RMI 実装が使用するデフォルトのソケットではなく、カスタムソケットファクトリを使用します。
このアプリケーションは、次の
Hello
リモートインタフェースを使用します。package examples.rmisocfac; public interface Hello extends java.rmi.Remote { String sayHello() throws java.rmi.RemoteException; }このサーバアプリケーションは、Hello
リモートインタフェースを実装するリモートオブジェクトを作成してエクスポートし、カスタムソケットファクトリを引数にとるjava.rmi.server.UnicastRemoteObject.exportObject
メソッドを使ってソケットファクトリを使用します。次に、ローカルレジストリを作成し、そのレジストリ内で、リモートオブジェクトのスタブへの参照を「Hello」という名前でバインドします。package examples.rmisocfac; import java.io.*; import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.*; public class HelloImpl implements Hello { public HelloImpl() {} public String sayHello( ) { return "Hello World!"; } public static void main(String args[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } byte pattern = (byte) 0xAC; try { /* * Create remote object and export it to use * custom socket factories. */ HelloImpl obj = new HelloImpl(); RMIClientSocketFactory csf = new XorClientSocketFactory(pattern); RMIServerSocketFactory ssf = new XorServerSocketFactory(pattern); Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0, csf, ssf); /* * Create a registry and bind stub in registry. * LocateRegistry.createRegistry(2002); Registry registry = LocateRegistry.getRegistry(2002); registry.rebind("Hello", stub); System.out.println("HelloImpl bound in registry"); } catch (Exception e) { System.out.println("HelloImpl exception:" + e.getMessage()); e.printStackTrace( ); } } }ステップ 2:
クライアントアプリケーションを作成するクライアントアプリケーションは、サーバアプリケーションが使用するレジストリへの参照を取得します。次に、リモートオブジェクトのスタブを検索して、リモートメソッド
sayHello
を呼び出します。package examples.rmisocfac; import java.rmi.*; import java.rmi.registry.*; public class HelloClient { public static void main(String args[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } try { Registry registry = LocateRegistry.getRegistry(2002); Hello obj = (Hello) registry.lookup("Hello"); String message = obj.sayHello(); System.out.println(message); } catch (Exception e) { System.out.println("HelloClient exception: " + e.getMessage()); e.printStackTrace( ); } } }
アプリケーションのコンパイルおよび実行は、次の 4 つのステップで行います。
ステップ 1:
リモートインタフェース、クライアント、およびサーバの各クラスをコンパイルするjavac -d .XorInputStream.java javac -d .XorOutputStream.java javac -d .XorSocket.java javac -d .XorServerSocket.java javac -d .XorServerSocketFactory.java javac -d .XorClientSocketFactory.java javac -d .Hello.java javac -d .HelloClient.java javac -d .HelloImpl.javaステップ 2:
実装クラス上でrmic
を実行する (オプション)注: リモートオブジェクトのクラスに対応するスタブクラスを事前に生成するための
rmic
は、リモートオブジェクトがリリース 5.0 より前のクライアントをサポートする必要がある場合にだけ実行する必要があります。リリース 5.0 では、リモートオブジェクトのエクスポート時にそのリモートオブジェクトのクラスに対応する事前生成のスタブクラスをロードできないと、リモートオブジェクトのスタブクラスが動的に生成されます。rmic -d . examples.rmisocfac.HelloImpljava -Djava.security.policy=policy examples.rmisocfac.HelloImplサーバ側の出力は、次のようになります。
HelloImpl bound in registry別のウィンドウでクライアントアプリケーションを起動し、アプリケーションのクラスが次のクラスパス内にあることを確認します。
java -Djava.security.policy=policy examples.rmisocfac.HelloClientクライアント側の出力は次のようになります。
Hello World!注: このサーバアプリケーションとクライアントアプリケーションはどちらも、セキュリティポリシーファイルを使用して、ローカルのクラスパス (カレントディレクトリ) 内のファイルへのアクセス権のみを付与します。サーバアプリケーションは接続を受け入れる権限を必要とし、サーバアプリケーションとクライアントアプリケーションの両方が、接続を作成する権限を必要とします。指定されたコードベース URL (カレントディレクトリからの相対位置を表す「file:」URL) にアクセス権
java.net.SocketPermission
が付与されます。このアクセス権では、特権を持たないポート (1024 以上のポート) 上で、任意のホストからの接続を受け入れること、および任意のホストへの接続を行うことが許可されます。grant codeBase "file:." { permission java.net.SocketPermission "*:1024-", "connect,accept"; };
レジストリの通信を保護するなど、レジストリへの通信は、適切なカスタムソケットファクトリを LocateRegistry.createRegistry
および LocateRegistry.getRegstry
呼び出しに渡すことによって、カスタマイズできることに注意してください。
Copyright © 2004 Sun Microsystems, Inc.All Rights Reserved. コメントの送付先: rmi-comments@java.sun.com |