Casual Developers Note

エンジニアやデザイナー向けの技術情報・英語学習情報・海外留学情報・海外旅行情報を提供中。世界を旅して人生を楽しもう。

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • お問い合わせ
現在の場所:ホーム / 技術 Tips & Tutorials / [tips][Java] RMIチュートリアル

2015年3月7日 By KD コメントを書く

[tips][Java] RMIチュートリアル

[tips][Java] RMIチュートリアル

かなり久しぶりの投稿になりました。社畜なうのKeidです。20代なので油断していましたが、地味に体調を崩してしまったので、健康を意識するようになってきました。そろそろ、Next Step、転職か起業して、会社に縛られない自由なエンジニアライフを手にしたいところです。自由と時間がほしい!最近RMIのアプリケーションを作るお仕事があったので、ついでにチュートリアルを作ってみました。

見出し

  • 1 RMIとは?
  • 2 リモートオブジェクトの作成
  • 3 RMIサーバーの作成
  • 4 RMIクライアントの作成
  • 5 rmiregistryコマンドによるRMIアプリケーション実行
  • 6 LocateRegistry#createRegistryによるRMIアプリケーションの実行
    • 6.1 関連記事

RMIとは?

RMIとは、Remote Method Invocationの略で、異なるホスト間でJavaオブジェクトのメソッドを実行するための通信手段です。

チュートリアルを開始する前に、RMIの動きを簡単に説明しておきます。RMIの仕組みの詳細はOracleさんのサイトを見てください。

RMIアプリケーションのアクターは、「RMIサーバー」、「RMIクライアント」、「RMIレジストリ」で、クライアントとサーバーでやり取りするためのJavaオブジェクトを「リモートオブジェクト」と言います。RMIサーバーは起動時にリモートオブジェクトをRMIレジストリに登録(bind)し、RMIクライアントは起動時にRMIレジストリからリモートオブジェクトを取得(lookup)して、リモートオブジェクトのメソッドを実行する、というフローになります。

RMIレジストリの実行には、rmiregistryコマンドを使う方法とLocateRegistry#createRegistryを使う方法がありますので、このチュートリアルでは両方やってみましょう。それでは、Let’s coding !

リモートオブジェクトの作成

(1) リモートオブジェクトのインターフェースを作る。

/**
 * Copyright (c) 2015, Keid All rights reserved.
 */
package rmi.remote;

import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 * Remote object
 * @author keid
 */
public interface Messenger extends Remote{
	
	/**
	 * send client's message
	 * @param message
	 * @return client's message
	 * @throws RemoteException
	 */
	public default String send(String message) throws RemoteException{
		System.out.println("client says "" + message + "".");
		return "send "" + message + "" to server.";
	}
	
}

(2) リモートオブジェクトの実装を作る。

/**
 * Copyright (c) 2015, Keid All rights reserved.
 */
package rmi.remote;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

/**
 * Remote object implementation
 * @author keid
 */
public class MessengerImpl extends UnicastRemoteObject implements Messenger{

	/**
	 * constructor of UnicastRemoteObject
	 * @throws RemoteException
	 */
	public MessengerImpl() throws RemoteException {
		super();
	}

	/**
	 * serial version
	 */
	private static final long serialVersionUID = 1L;

}

RMIサーバーの作成

(1) RMIサーバーのインターフェースを作る。

/**
 * Copyright (c) 2015, Keid All rights reserved.
 */
package rmi.server;

import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.Naming;

import java.rmi.RemoteException;
import java.net.MalformedURLException;

/**
 * Rmi server
 * @author keid
 */
public interface RmiServer{

	/**
	 * start server
	 * @throws RemoteException
	 * @throws MalformedURLException
	 */
	public void start() throws RemoteException, MalformedURLException;
	
	/**
	 * start server via Registry
	 * @param host
	 * @param port
	 * @param serverName
	 * @param remoteObject
	 * @throws RemoteException
	 */
	public default void start(String host, int port, String serverName, Remote remoteObject) throws RemoteException{
		
		// rmi url
		String url = "rmi://"+ host + ":" + Integer.toString(port) +"/" + serverName;
						
		// bind remote object to rmiregistry
		System.out.println("bind "" + url + "" to rmiregistry");			
		Registry rmiregistry = LocateRegistry.createRegistry(port);
		rmiregistry.rebind(url, remoteObject);

		System.out.println("Rmi server starting...");
			
	}

	/**
	 * start server via rmiregistry process
	 * @param host
	 * @param port
	 * @param serverName
	 * @param remoteObject
	 * @throws RemoteException
	 * @throws MalformedURLException
	 */
	public default void startViaProcess(String host, int port, String serverName, Remote remoteObject) throws RemoteException, MalformedURLException{
		
		// rmi url
		String url = "rmi://"+ host + ":" + Integer.toString(port) +"/" + serverName;
						
		// bind remote object to rmiregistry
		System.out.println("bind "" + url + "" to rmiregistry");
		Naming.rebind(url, remoteObject);

		System.out.println("Rmi server starting...");
			
	}
	
}

(2) RMIサーバーの実装を作る。

/**
 * Copyright (c) 2015, Keid All rights reserved.
 */
package rmi.server;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.Remote;
import java.rmi.RemoteException;

import rmi.remote.Messenger;
import rmi.remote.MessengerImpl;

/**
 * Rmi server implementation
 * @author keid
 */
public class RmiServerImpl implements RmiServer{

	private String host;
	private int port;
	private String serverName;
	private Remote remoteObject;

	public RmiServerImpl(String host, int port, String serverName, Remote remoteObject){
		this.host = host;
		this.port = port;
		this.serverName = serverName;
		this.remoteObject = remoteObject;
	}
	
	@Override
	public void start() throws RemoteException, MalformedURLException{
		//start(host, port, serverName, remoteObject);
		startViaProcess(host, port, serverName, remoteObject);
	}
		
	/**
	 * server main program
	 * @param args
	 */
	public static void main(String[] args){
				
		try {

			//String host = "localhost";
			String host = InetAddress.getLocalHost().getHostAddress();
			int port = 1099;
			String serverName = "server";
			Messenger messenger = new MessengerImpl();

			RmiServer server = new RmiServerImpl(host, port, serverName, messenger);
			server.start();

		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}

}

RMIクライアントの作成

(1) RMIクライアントのインターフェースを作る。

/**
 * Copyright (c) 2015, Keid All rights reserved.
 */
package rmi.client;

import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.Naming;

import java.rmi.RemoteException;
import java.rmi.NotBoundException;
import java.net.MalformedURLException;

/**
 * Rmi client
 * @author keid
 */
public interface RmiClient {
		
	/**
	 * lookup remote object
	 * @return remote object
	 * @throws RemoteException
	 * @throws NotBoundException
	 * @throws MalformedURLException
	 */
	public Remote lookup() throws RemoteException, NotBoundException, MalformedURLException;
	
	/**
	 * lookup via Registry
	 * @param host
	 * @param port
	 * @param serverName
	 * @return remote object
	 * @throws RemoteException
	 * @throws NotBoundException
	 */
	public default Remote lookup(String host, int port, String serverName) throws RemoteException, NotBoundException{
		
		// rmi url
		String url = "rmi://"+ host + ":" + Integer.toString(port) +"/" + serverName;
						
		// lookup remote object from rmiregistry
		System.out.println("lookup "" + url + "" from rmiregistry");	
		Registry rmiregistry = LocateRegistry.getRegistry(port);

		return rmiregistry.lookup(url);
	
	}
	
	/**
	 * lookup via rmiregistry process
	 * @param host
	 * @param port
	 * @param serverName
	 * @return remote object
	 * @throws RemoteException
	 * @throws NotBoundException
	 * @throws MalformedURLException
	 */
	public default Remote lookupViaProcess(String host, int port, String serverName) throws RemoteException, NotBoundException, MalformedURLException{
		
		// rmi url
		String url = "rmi://"+ host + ":" + Integer.toString(port) +"/" + serverName;
						
		// lookup remote object from rmiregistry
		System.out.println("lookup "" + url + "" from rmiregistry");	

		return Naming.lookup(url);
	
	}

}

(2) RMIクライアントの実装を作る。

/**
 * Copyright (c) 2015, Keid All rights reserved.		
 */
package rmi.client;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;

import rmi.remote.Messenger;

/**
 * Rmi client implementation
 * @author keid
 */
public class RmiClientImpl implements RmiClient{
	
	private String host;
	private int port;
	private String serverName;
	
	public RmiClientImpl(String host, int port, String serverName){
		this.host = host;
		this.port = port;
		this.serverName = serverName;
	}
	
	@Override
	public Remote lookup() throws RemoteException, NotBoundException, MalformedURLException{
		//return lookup(host, port, serverName);
		return lookupViaProcess(host, port, serverName);
	}
	
	/**
	 * client main program
	 * @param args
	 */
	public static void main(String[] args){
		
		String message = "Hey, Keid!";
		
		try {
			
			//String host = "localhost";
			String host = InetAddress.getLocalHost().getHostAddress();
			int port = 1099;
			String serverName = "server";
			
			RmiClient client = new RmiClientImpl(host, port, serverName);
			Messenger messenger = (Messenger) client.lookup();
			System.out.println(messenger.send(message));
		
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (NotBoundException e) {
			e.printStackTrace();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}

	}

}

rmiregistryコマンドによるRMIアプリケーション実行

(1) RMIコマンドを実行する。

ターミナルを開いて、以下のコマンドを実行します。ポートは1099にします。

$ rmiregistry 1099

コマンドを実行した時にリモートオブジェクトに対してjava.lang.ClassNotFoundExceptionが発生する場合があります。これは、リモートオブジェクトの場所が分からなかったことが原因なので、コマンド実行時にクラスパスを指定してあげればよいです。

クラスパスをcodebaseで指定する場合は以下のコマンドを実行します。

$ rmiregistry -J-Djava.rmi.server.codebase=file:///クラスパス 1099

クラスパスをCLASSPATHで指定する場合は以下のコマンドを実行します。

$ rmiregistry  -J-cp -JC:クラスパス 1099

codebaseはJVMに対してロードするクラスの場所を教える時に使用します。リモートにあるクラスパスを指定することが可能です。(RMIサーバーとRMIクライアントが別のホストの場合)一方、CLASSPATHはローカルなcodebaseを指定していることになります。(RMIサーバーとRMIクライアントが同じホストの場合)

一応、rmiregistryプロセスの停止方法ですが、上記のコマンドで実行した場合は、「control+c」で停止できます。実行時に「&」をつけてバックグラウンドで実行した場合は、psコマンドとgrepコマンドを組み合わせて PIDを検索し、killコマンドで停止させます。例としては以下のようにします。

$ rmiregistry &
$ ps -ax | grep rmiregistry
38247 ttys000    0:00.26 /usr/bin/rmiregistry
38254 ttys000    0:00.00 grep rmiregistry
$ kill 38247

(2) RMIサーバーを起動する。

RmiServerImplをrunします。(eclipseでもjavaコマンドでもOK)

<RMIサーバーのコンソール>

bind "rmi://IPアドレス:1099/server" to rmiregistry
Rmi server starting...

(3) RMIクライアントを起動する。

RmiClientImplをrunします。(eclipseでもjavaコマンドでもOK)

<RMIクライアントのコンソール>

lookup "rmi://IPアドレス:1099/server" from rmiregistry
send "Hey, Keid!" to server.

<RMIサーバーのコンソール>

bind "rmi://IPアドレス:1099/server" to rmiregistry
Rmi server starting...
client says "Hey, Keid!".

LocateRegistry#createRegistryによるRMIアプリケーションの実行

(1) RMIサーバーとRMIクライアントの実装を変更する。

お気付きの方もいると思いますが、最初からこのパターンの実装も組み込んであるので、実装クラスを少し変更するだけで、実行できます。RMIサーバーおよびRMIクライアントの変更点は以下です。

<RmiServerImplの変更点>

	@Override
	public void start() throws RemoteException, MalformedURLException{
		start(host, port, serverName, remoteObject);
		//startViaProcess(host, port, serverName, remoteObject);
	}

<RmiClientImplの変更点>

	@Override
	public Remote lookup() throws RemoteException, NotBoundException, MalformedURLException{
		return lookup(host, port, serverName);
		//return lookupViaProcess(host, port, serverName);
	}

この変更で、rmiregistryコマンドの実行が不要になりました。

(2) RMIサーバーを起動する。

RmiServerImplをrunして、rmiregistryコマンドによるRMIアプリケーション実行と同じ表示になれば成功です。

(3) RMIクライアントを起動する。

RmiClientImplをrunして、rmiregistryコマンドによるRMIアプリケーション実行と同じ表示になれば成功です。

That’s all.

これで、RMIの基本はマスターできたと思います。RMIを実際に使う場面ではTomcatアプリケーション化することが多いと思うので、リモートオブジェクトの破棄(UnicastRemoteObject#unexportObject)には注意しましょう。今回は不要です。

Tumblerでソースコード多めの記事をまとめるのはしんどいですね。だから、更新頻度が上がらないのかも。ところで、ソースコードのインターフェースにやたらとdefaultを使っていますが、ただ単にJava8で導入されたので使ってみただけです(笑)

<環境>
OS : OS X Yosemite 10.10.2
Java : 1.8.0_31

The following two tabs change content below.
  • この記事を書いた人
  • 最新の記事
KD
Twitter のプロフィール

KD

世界を旅し日本を愛するエンジニア。大学でコンピュータサイエンスの楽しさを学び、日本の大手IT企業で働く中で、新しい技術やスケールするビジネスが北米にある事に気づく。世界に挑戦するための最大の壁が英語であったため、フィリピン留学およびカナダ留学を経て英語を上達させた。現在は日本在住でエンジニアとして働きつつ、次の挑戦に備えて世界の動向を注視している。挑戦に終わりはない。このブログでは、エンジニアやデザイナー向けの技術情報から、海外に留学したい人向けの留学情報、海外に興味がある人向けの海外旅行情報など、有益な情報を提供しています。
KD
Twitter のプロフィール

最新記事 by KD (全て見る)

  • 2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介 - 2020年1月13日
  • 今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~ - 2019年11月4日
  • ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~ - 2019年10月30日

関連記事

  • [tips][Kotlin] GradleでKotlin入門

    皆さん、お久しぶりです。Keidです。 気づくとかなり更新していませんでした。 え、何してたって?炎上案件に決まってるで…

  • [tips][Tool] MacでRubyとPythonとJavaとNodeとPerlの複数バージョンを管理する方法

    iPhone6sですか?予約しました、Keidです。 今月で20代ラストの年になってしまいました。30代が目前になるとい…

  • [tips][Windows][SSH] Windows版OpenSSHでSSHサーバを構築する方法

    Windowsを使うエンジニアは誰もがこう考えます。LinuxのようにWindowsを使いたいと。LinuxサーバにSS…

カテゴリ : 技術 Tips & Tutorials タグ : java, mac, rmi, tips, tumblr-imported

コメントを残す コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。

ブログ更新情報や海外の関連情報などを配信する無料メルマガ

Sponsored Links

About Author

KD

世界を旅し日本を愛するエンジニア。大学でコンピュータサイエンスの楽しさを学び、日本の大手IT企業で働く中で、新しい技術やスケールするビジネスが北米にある事に気づく。世界に挑戦するための最大の壁が英語であったため、フィリピン留学およびカナダ留学を経て英語を上達させた。現在は日本在住でエンジニアとして働きつつ、次の挑戦に備えて世界の動向を注視している。挑戦に終わりはない。このブログでは、エンジニアやデザイナー向けの技術情報から、海外に留学したい人向けの留学情報、海外に興味がある人向けの海外旅行情報など、有益な情報を提供しています。

https://casualdevelopers.com/

最近の投稿

  • 2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年1月13日
  • 今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    2019年11月4日
  • ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    2019年10月30日
  • BashからZshに移行する方法(Mac編)

    BashからZshに移行する方法(Mac編)

    2019年10月21日
  • Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    2019年9月30日

カテゴリ

  • 技術 Tips & Tutorials (100)
  • 技術塾 (6)
  • ライフハック (26)
  • 海外留学 (12)
  • 英語学習 (3)
  • コラム (6)

アーカイブ

最高の学習のために

人気記事ランキング

  • MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
    MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
  • SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
    SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
  • Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
    Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
  • AWS ECRとECSの入門(EC2編) ~ ECSのEC2版を使ってReactのDockerアプリケーションをAWS上で稼働させる方法 ~
    AWS ECRとECSの入門(EC2編) ~ ECSのEC2版を使ってReactのDockerアプリケーションをAWS上で稼働させる方法 ~
  • 爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~
    爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~
  • Amazon EC2インスタンスにSSHできなくなった時の対処法
    Amazon EC2インスタンスにSSHできなくなった時の対処法
  • バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
    バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
  • [tips][bat] バッチで明日の日付を計算する。
    [tips][bat] バッチで明日の日付を計算する。
  • Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
    Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
  • [tips][perl] Perlで文字コードをいい感じに処理する方法
    [tips][perl] Perlで文字コードをいい感じに処理する方法

Bitcoin寄付 / BTC Donation

Bitcoinを寄付しよう

BTC
Select Payment Method
Personal Info

Donation Total: BTC 0.0010

このブログの運営のためにBitcoinでの寄付を募集しています。お気持ち程度の寄付を頂けると管理者の励みになります。

Bitcoin寄付について知りたい方はこちらの記事へ

The following two tabs change content below.
  • この記事を書いた人
  • 最新の記事
KD
Twitter のプロフィール

KD

世界を旅し日本を愛するエンジニア。大学でコンピュータサイエンスの楽しさを学び、日本の大手IT企業で働く中で、新しい技術やスケールするビジネスが北米にある事に気づく。世界に挑戦するための最大の壁が英語であったため、フィリピン留学およびカナダ留学を経て英語を上達させた。現在は日本在住でエンジニアとして働きつつ、次の挑戦に備えて世界の動向を注視している。挑戦に終わりはない。このブログでは、エンジニアやデザイナー向けの技術情報から、海外に留学したい人向けの留学情報、海外に興味がある人向けの海外旅行情報など、有益な情報を提供しています。
KD
Twitter のプロフィール

最新記事 by KD (全て見る)

  • 2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介 - 2020年1月13日
  • 今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~ - 2019年11月4日
  • ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~ - 2019年10月30日

関連記事

  • [tips][Kotlin] GradleでKotlin入門

    皆さん、お久しぶりです。Keidです。 気づくとかなり更新していませんでした。 え、何してたって?炎上案件に決まってるで…

  • [tips][Tool] MacでRubyとPythonとJavaとNodeとPerlの複数バージョンを管理する方法

    iPhone6sですか?予約しました、Keidです。 今月で20代ラストの年になってしまいました。30代が目前になるとい…

  • [tips][Windows][SSH] Windows版OpenSSHでSSHサーバを構築する方法

    Windowsを使うエンジニアは誰もがこう考えます。LinuxのようにWindowsを使いたいと。LinuxサーバにSS…

ビットコイン取引ならここ

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • サイトマップ
  • タグ一覧
  • プライバシーポリシー
  • お問い合わせ

Copyright © 2023 KD - Casual Developers Notes