takeda_san’s blog

JavaFXと機械学習を頑張る方向。

GCPでもJavaがしたい その3

作業記録的なやつです。

作業予定

  1. GCPアカウント作成
  2. Webサーバをたててみる
  3. JREをいれて何か動かしてみる
  4. RMIで通信してみる ←今回はここ
  5. Dockerイメージをつくってみる
  6. クラスタ環境をつくってみる
  7. コンテナを動かしてみる
  8. RMIで通信してみる(コンテナ編)

…ちょっとやる内容変わってるけど気にしない。 JavaFXでクライアント作るのが、ちょっとめんどくさかっただけ。

なぜRMIなのか

Javaでサーバ通信で簡単なやつ…と考えたときにJavaSEだしコンソールで簡単にできそうという理由。
あとポート開けたり、セキュリティの設定で躓く姿が今から想像できてワクワクするから。

コード

クライアントから送った文字列にちょっと付け足して送り返すだけのやつ。
見づらいので記事にコードを書かないでgithubに上げたのを貼り付ける。
ナウイ。

インタフェース

サーバ

クライアント

ローカルで動作確認してみる

なれないIntelliJでやったので、これだけで3時間ぐらいかかったのは秘密。

モジュールの配置の仕方

このコードをサーバ側用とクライアント用に分けてjarファイルとして出力する。
RmiServer.jar→サーバ用
RmiClient.jar→クライアント用

rmiregistry起動編

クラスパスを指定する方法で起動します。
例えばworkってディレクトリにjarを入れてあるって前提。
あと無駄にJava 9でやる。

set CLASSPATH=C:\work\RmiServer.jar
"C:\Program Files\Java\jre-9\bin\rmiregistry.exe"

もちろん、パス通してればrmiregistry.exeで大丈夫。

サーバ起動編

普通にjar実行。

java -jar C:\work\RmiServer.jar

クライアント起動編

起動時引数に接続先のホスト名を入れるようになっているので、localhostと指定してjar実行。

java -jar C:\work\RmiClient.jar localhost

実行結果

from server:こんにちは!!

インスタンスと通信をしてみよう

まずはファイルをアップロード

まず、インスタンスを生成して、jdk入れる。
そしてファイルのアップデートなんだけれど…どうやるんだ?ドキュメントを見に行こうか。
なんとコマンドでファイルがアップロードできるらしい。

gcloud compute copy-files [LOCAL_FILE_PATH] [INSTANCE_NAME]:~/
gcloud compute copy-files` is deprecated.  Please use `gcloud compute scp` instead

えぇ、非推奨なの…?
多分日本語のヘルプが古いんだね。
英語勉強しなさいってことだね。

というわけで、よくわからんのでWinSCPをインストールしてアップロードにします。
設定はここに書いてある通り。

インスタンスへのファイルの転送  |  Compute Engine ドキュメント  |  Google Cloud Platform

んで、WinSCPで使用するために秘密鍵と公開鍵が必要なんだけど、自分で生成して登録してあげなきゃならないみたい。
基本的には下の通りなんだけど、公開鍵をSSH認証鍵として登録するときにちょっとフォーマットを変えてあげなきゃいけないみたい。

GCEにPuttyから簡単接続する|apps-gcp.com|G Suite(旧:Google Apps) やGoogle Cloud Platform サービスについて紹介します

無効な鍵です。次の形式にする必要があります: <protocol> <key-blob> <username@example.com> または <protocol> <key-blob> google-ssh {"userName":"<username@example.com>","expireOn":"<date>"}

なので、ssh-rsa 公開鍵 hogehoge@gmail.comみたいな感じに書き換えて登録しておく。
そして、接続成功。
RmiServer.jarファイルをささっとアップロード。

いざ実行

まずはサーバ側の準備
クラスパスの設定~rmiサーバの起動
(jarは、とりあえずrootにおいてみた)

export CLASSPATH=/root/RmiServer.jar
rmiregistry &
java -jar ./RmiServer.jar 

そして、クライアントを起動してみる。

java.rmi.ConnectException: Connection refused to host: 10.142.xxx.xxx; nested exception is: 
    java.net.ConnectException: Connection timed out: connect

あっ…ですよねー。
接続失敗してるIPが内部IPに変わってるのが、気になるが先にファイアウォールの設定かな…
GCPのダッシュボードの検索窓からファイアウォールで出てきたVPCネットワークファイアウォールルール ってところから設定するっぽい。
これを参考にしながらTCPのポート1099を開ける。

dev.classmethod.jp

もう一度、実行。

java.rmi.ConnectException: Connection refused to host: 10.142.xxx.xxx; nested exception is: 
    java.net.ConnectException: Connection timed out: connect

う、うーん。
やっぱり、内部IPに変わってるのが気になるので調べてみる。

netbuffalo.doorblog.jp

あっ、これっすね。
サーバの起動時の引数に-Djava.rmi.server.hostname=[外部IPアドレス]を加えてあげる
なんか初回はサーバが立ち上がるまで、1分ぐらいかかった。
んで、どうやら1099ともうひとつ別のポートを開かなきゃいけないみたいなんだけど匿名ポートから任意のポートに変える方法が今いちわからなかった…
なので、tcp全空け。

dstn.appresso.com

ここのサイトに書いてある通りだと思うんだけど、濃すぎるキャラクターのせいで理解を阻害された感ある。
うん、いいわけ。
そして、リトライ。

java -jar -Djava.rmi.server.hostname=104.196.xxx.xxx ./RmiServer.jar
from server:こんにちは!!

GCPとは別なところでハマったけど、RMIの勉強になったからいいか。

まとめ

情報がとっちらかってるので、RMIしたいけどクライアントとサーバが別な時にやることまとめ。

クライアント編

とくになし。
いつも通りに起動しましょう。

サーバ編

  • ファイアウォールを設定しましょう rmiregistryで使うデフォルトポート1099とリモートメソッド呼び出し時につなぎに行くポート(匿名ポート)をTCPで開ける。

  • リモートメソッド呼び出し時につなぎに行く先の指定 -Djava.rmi.server.hostname=[外部IPアドレス]でつなぎに行く先を指定してあげる。
    ほかにも方法はある模様。

Java RMI ConnectException: Connection refused to host: 127.0.0.1 エラーの正しい理解と対策

あー、なんか疲れた。