2014年12月21日

Java8の暗号利用モードのGCMって遅すぎない?

去年作ったファイル転送WebアプリをGlassFish4.1とJava8に載せ替えたんだけど、
それだけで、凄ーく遅くなったの。
載せ替える前はGlassFish4だからJava7で動いてたんだよね。
あ、ハードはfit-PC2iのWindows8(32bit)で動いてるよ。

実際に測定するとこんな感じ。

ファイル転送Webアプリの転送速度(インターネットを経由させて測定)
サーバー 速度
Java7 GlassFish4.0 26000〜28000bps
Java8 GlassFish4.1 2600〜2800bps

うん、超遅くなった。あり得ないよね、ほんと。

わたしが作った部分がおかしいのかなーとか思って、プログラムを見たんだけど、
ファイルの書き込みくらいしか重そうな処理がなったんだよね。
ファイルIOが遅いのかなーって思って、ファイルの書き込み処理を外すとこんな感じ。

ファイル転送Webアプリの転送速度(インターネットを経由させて測定:書き込み処理無し)
サーバー 速度
Java7 GlassFish4.0 26000〜28000bps
Java8 GlassFish4.1 2600〜2800bps

変わんないし!全く変わんないし!

ファイル転送のWebアプリだから、ファイルの書き込み取っちゃったら、何も残らないのに……。
と言うことで、JavaとGlassFishに問題がないか探すことに。
まぁ、普通に考えると、GlassFish側かな?Javaなコアなところはみんな触ってるだろうし。

とはいえまずは実測実測。パフォーマンス測定の基本は実測だよね!
GlasFish4.1はJava7でも動くはずだから計ってみた。

ファイル転送Webアプリの転送速度(インターネットを経由させて測定)
サーバー 速度
Java7 GlassFish4.1 26000〜28000bps

あれ……。えーっと……。遅くならない……。
Javaのコアな部分に問題があるってこと……???(゜▽、゜
もうわたしにはわからない、わからないよ。

こうなったらもうプロファイル?を見るしかないよね!
と言うことで、NetBeansのプロファイル機能を見てみる。

Java8で時間がかかってるあたり
call_hierarchy.png

うん、完全にSSLの復号化のところですっごい時間かかってるね。
同じあたりをJava7とJava8で比較してみる。

Java7の呼び出しツリー
call_hierarchy_jdk7.png

Java8の呼び出しツリー
call_hierarchy_jdk7.png

Java8は結構呼び出しを展開してみたんだけど、同じ呼び出しが延々深く続いてるだけみたい。
NetBeansが重くなって最後まで開けなかったけど。

ここから分かるのは、Java7の方は、『AES』とか『CihperBlockChaining』とかが見えるんだけど、
Java8の方は、『AES』の他に、『GaloisCounterMode』とか『GHASH』とかが見える。
使われている暗号化の方式が変わってる……?

Oracleのサイトを見ると、Java7からJava8になったときにGCMって言うのが増えてるんだね。
https://docs.oracle.com/javase/jp/8/technotes/guides/security/SunProviders.html

これか!これが悪さしてるのか!新しいのに遅いなんて!

と、決めつける前に、確認確認。
Java7とJava8とで、それぞれのGlassFish4.1のセキュリティ設定を確認してみる。

Java7のセキュリティ設定
ciphers_jdk7.png

Java8のセキュリティ設定
ciphers_jdk8.png

たしかに、Java8の方が多くなってる〜。
これでJava8の時の暗号化方式をGCM以外から選ぶように設定ッと。
select_without_gcm.png

測定しなおした結果はこんな感じ。

ファイル転送Webアプリの転送速度(インターネットを経由させて測定:GCM除外)
サーバー 速度
Java8 GlassFish4.1 26000〜28000bps

速くなった!原因はGCM、これだね!

GlassFish4.1が関係ないことを確認するために、
Java8で実際に検証コードを書いてみる。

こんな感じ。大きく差が出るだろうから、適当で良いよね。

CBC

	int length = 200000000;
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
Key key = keyGenerator.generateKey();
IvParameterSpec parameters = new IvParameterSpec(new byte[16]);
Cipher CBCEncrypter = Cipher.getInstance("AES/CBC/PKCS5Padding");
CBCEncrypter.init(Cipher.ENCRYPT_MODE, key, parameters);
Cipher CBCDecrypter = Cipher.getInstance("AES/CBC/PKCS5Padding");
CBCDecrypter.init(Cipher.DECRYPT_MODE, key, parameters);
byte[] targetBytes = new byte[length];
long time0 = System.currentTimeMillis();
byte[] encryptedBytes = CBCEncrypter.doFinal(targetBytes);
long time1 = System.currentTimeMillis();
byte[] decryptedBytes = CBCDecrypter.doFinal(encryptedBytes);
long time2 = System.currentTimeMillis();
System.out.println(Arrays.equals(targetBytes, decryptedBytes));
System.out.println("暗号化時間:" + (time1 - time0) + "ミリ秒");
System.out.println("復号化時間:" + (time2 - time1) + "ミリ秒");

GCM

	int length = 200000000;
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
Key key = keyGenerator.generateKey();
GCMParameterSpec parameters = new GCMParameterSpec(128, new byte[16]);
Cipher GCMEncrypter = Cipher.getInstance("AES/GCM/PKCS5Padding");
GCMEncrypter.init(Cipher.ENCRYPT_MODE, key, parameters);
Cipher GCMDecrypter = Cipher.getInstance("AES/GCM/PKCS5Padding");
GCMDecrypter.init(Cipher.DECRYPT_MODE, key, parameters);
byte[] targetBytes = new byte[length];
long time0 = System.currentTimeMillis();
byte[] encryptedBytes = GCMEncrypter.doFinal(targetBytes);
long time1 = System.currentTimeMillis();
byte[] decryptedBytes = GCMDecrypter.doFinal(encryptedBytes);
long time2 = System.currentTimeMillis();
System.out.println(Arrays.equals(targetBytes, decryptedBytes));
System.out.println("暗号化時間:" + (time1 - time0) + "ミリ秒");
System.out.println("復号化時間:" + (time2 - time1) + "ミリ秒");

測定結果は、こんな感じ〜。

# バイト数 時間(ミリ秒)  
CBC GCM GCM/CBC
暗号化 復号化 暗号化 復号化 暗号化 復号化 AVG
1 100000 16 24 160 96 10.0 4.0 7.0
2 100000 16 24 160 96 10.0 4.0 7.0
3 1000000 64 88 1000 915 15.6 10.4 13.0
4 1000000 56 88 1016 912 18.1 10.4 14.3
5 10000000 392 400 8483 7852 21.6 19.6 20.6
6 10000000 376 368 7881 8004 21.0 21.8 21.4
7 100000000 3060 3351 53760 68640 17.6 20.5 19.0
8 100000000 3065 3325 74182 72976 24.2 21.9 23.1
9 100000000 2720 3142 61908 64244 22.8 20.4 21.6
10 200000000 4886 5103 110236 102925 22.6 20.2 21.4
11 200000000 6267 6223 125277 110626 20.0 17.8 18.9
12 200000000 5658 6211 124878 124675 22.1 20.1 21.1

 

うん、サイズが小さいときも遅いけど、サイズが大きくなってくるとだいたい20倍くらい遅いね!これはひどい(゜▽、゜
GCMのWikipedia見た感じだと、速くなりそうなのにね。
遅いにしても限度って言うものがあると思うんだけど……。
もしかして、去年Windowsのアプリが遅くなったのも何か関係あったりするのかな?
暗号化は、WindowsのNativeなAPI使ってるとか……?

まぁ、とりあえず直ったから良いよね(゚ー゚)(。_。)(゚-゚)(。_。)ウンウン

posted by すふぃあ at 21:00| Comment(3) | TrackBack(0) | 雁字

JavaEEなWebアプリケーションを作ろうとしたときのお話

☆はじめに☆

この記事はJava Advent Calendar 2014の12月21日分の記事だよ。

前は、2012年の時にAndroidの話を書いたんだけど、
今回は、Webアプリケーションを作ろうとしたときの話を書くのだ。

☆導入☆

去年の12月くらいに、いつも使ってたWindowsのファイル転送アプリが凄ーく遅くなって、
もう、これは耐えられない!ってことで、代わりにGlassFish4のWebSocketを使ったファイル転送Webアプリを作ったの。

で、先月、他にもなんかWebアプリケーションを作ってみようかなって思って、
ついでだからGlassFishを4.1にバージョンアップ!さらにJavaも7から8にバージョンアップ!したんだけど、
そのとたんに、ファイル転送Webアプリの速度が凄〜く遅くなったんだよね。

と言うわけで前編はその時のお話だよ。

で、遅いのは解決したんだけど、
新しいWebアプリは、ただ、転送するだけのアプリと違って、
いろいろ作りたかったから、
ちょっとがんばってユニットテストも作ろうかな!って思ったんだよね。

と言うわけで後編はその時のお話だったり。

ちなみに、今回作ったWebアプリケーション自体については何も書いてなかったりする(゜▽、゜

それと、今回はホント、ネタのあたりから、検証あたりとか、いろいろ協力してもらえて助かったのだ(゚ー゚)(。_。)(゚-゚)(。_。)ウンウン
間接的にも助けてもらったりしたし、みんなに感謝なのだ(゜▽、゜

posted by すふぃあ at 21:00| Comment(1) | TrackBack(0) | 雁字

2012年12月08日

Androidのjava.util.zipパッケージと戦った記憶

この記事はAdvent Calendar 2012 Javaの8日目だよ。

前の日の記事はryu22e(@ryu22)さんで、
Javaのデータベースマイグレーションツール「Flyway」 #JJUG』だったね。
次の日の記事はHideki Kishida(@quicy)さんがやってくれるみたいだよ。

で、この記事では、わたしが最近作っている『コミみみ』って言うAndroidアプリの動きを確認していたときのことを淡々と書くのだ。
読みやすさは全く考えられていないので覚悟して読んでね。

コミみみ』って言うのは、コミックマーケット用のアプリ……まぁ、えっと、カタログViewerなんだけど、
サークルカット(画像)をZIPで1つのファイルにまとめたものを読み込んでいるんだ。
その読み込みをするときに問題が起こったの。

ZIPファイルをJavaで扱う定番は、java.util.zipパッケージのZipFileクラスだよね。
で、ZipFileクラスで有名な問題といえば、
開こうとしているZIPファイルに含まれているファイル数が65535個を超えていると開けないってこと。
ZIP64っていう拡張仕様までサポートしてないよってことだから、不具合と言うより仕様かな。
これはAndroidに限らずある問題だね。Java7ではサポートしたみたいだけど、AndroidはJava6までだし。

65535個って言うのは、unsigned short型(2バイト)での表現の限界から来ているみたい。
だから、ZIP64をサポートしないと、それより多いファイルを含むZIPファイルは開けない。

Androidでわたしがぶつかった問題も、この『含まれているファイルの数』によるものなの。
この問題をぐーぐるさんで検索すると『多すぎるからだよ!』って言うのがたくさんヒットするよ。

でも、カタログでサークルカットが多いって言っても、35000個くらいしかないんだよね……。
65535個を超えてなくても開けないっ。
試して見ると、だいたい32000個を超えてきたくらいで開けなくなるんだよね。

はい、これでわかっちゃうと思うけど、32767個を超えると開けなくなるみたい。
Javaにはunsignedな型はないから、
unsigned shortで表現されている『含まれているファイルの数』を持つためにはint型が必要になるんだよね。
short型は-32768〜32767までしか表現できないから。
たぶん、short型でファイルの数を持っちゃっておかしくなっているんだと思う。

あれ?でも、ちょっと待って。なんでこんな問題があるの?
java.util.zipパッケージなんて大昔からあるわけでしょ?
そこに、こんな問題があるなんておかしいでしょ!

で、調べてみるとAndorid 2.3.3系では発生しないんだよね。これ。
でも、Android 4.0.xでは発生するの。Android 3.xはどっちかな〜?まぁ、どっちでもいいよね。
つまり、これ、最近……でもないかもだけど、java.util.zipパッケージが書き換えられたことで起こっているみたい。

……え?やっぱり、おかしくない?
拡張仕様をサポートしたわけでもないのに、ZipFileの実装が書き換わってる……?

Android 2.3.3系は……大丈夫っ。でも、その後書き換えられておかしくなっている……。

もしかして、OracleとGoogleの訴訟の問題から来てたりするのかな?
やっぱりGoogle、やっちゃってたのかな?とか想像してみちゃった。
詳しいこと何も知らないけどね!

Android 4系のアプリサポートはこれからだろうから、
ZIPでファイルをいっぱい使うする人は気をつけようね。

そこ!ZIPファイルで数万もファイル扱うことなんて無いなんて言わないでっ!
あ、忘れるところだった。解決方法だけど、
  1. ZIPフォーマットは簡単だから自分で作る。
  2. Android 2.3.3系は動くからそっちから持ってくる。
  3. org.apache.tools.zipパッケージを使う。
って言う感じかな。最後のは、java.util.zipパッケージより20倍〜40倍遅いからやめた方が良いと思うけど。
posted by すふぃあ at 11:34| Comment(2) | TrackBack(0) | 雁字

2012年09月15日

Androidのライブラリを作ってみたよ

Empressia for Androidって

Android用のライブラリを作ってみたよ。
いくつか便利なクラスを用意してあるから、紹介するね。
※Android 2.3.3(API Level 10)以上、r16以上のSupport Library v4を使ってるよ。

DBUnit

JPAみたいな@Idと@Columnのアノテーションをデータクラスにつけて、
簡単にDBのやりとりをするクラスだよ。
SQLかかなくてすむわけじゃないけど、だいぶ楽になるんじゃないかな〜。

基本的には、継承して使ってね。たとえばこんな感じ。
public class HogeDBUnit extends DBUnit {
@Override
protected Class<?>[] getManagedClasses() {
return new Class<?>[] { DataClass1.class, /* DataClass2.class, DataClass3.class */ };
}
}
public class DataClass1 {
@Id @Column
public int ID;
@Column
public String Name;
}

これで、DBUnit使うときに適当なCREATE文が自動で作られてDBが準備されるよ。
アノテーションはsetterとかにつけてもok。

データを全部取ってくる場合は
List list = this.DBUnit.findAll(DataClass1.class, null);
これで全件取得できるよ。

まぁ、JOINとかWHEREとかを書くときは、全部自力で書かないといけないんだけどね。
でもオブジェクトにマッピングするところは自動でできるよ。

SharedPreferences

Androidに用意されてるSharedPreferencesのキーってStringなんだよね。
ローカライズするものじゃないからだと思うけど、キーをリソースにしたくなったりしない?
そういう場合は、このクラス。

SharedPreferences prefs = new SharedPreferences(originalPrefs);
こんな感じでラップすればリソースをキーに使えるよ。
SharedPreferences prefs = SharedPreferencesUtilities.getPrivate(context);
ってやれば、アプリ用の設定を一発で取ってくることもできるよ。
う〜ん、微妙?
キーをリテラルで埋め込んでるよりはましかな〜って思ったんだけど。 

AbstractListAdapter

ListAdapterでなんかViewのリサイクルとか考えるのが面倒だから、AbstractListAdapterって言うのを用意してみたよ。
createViewとupdateViewをそれぞれ実装すれば良いだけだから簡単だよ。

AbstractListPagerAdapter

ViewPager用のクラスを作ってみたよ。
ViewPagerは元々、いろんな見栄えのページを切り替えるために作られたと思うんだけど、
同じ見栄えのページをListViewみたいに連続して表示したいと思うことってない?

コンストラクタで、レイアウトと表示するデータのリストを渡すと、あとは自動で切り替えとかするよ。

updateViewでViewを書き換えるだけで横に1ページごとに切り替えられるListViewのできあがり。
PagerAdateprとか、FragmentPagerAdapter、FragmentStatePagerAdapterから作るよりも
楽に作れてメモリも節約できるんじゃないかな〜。

他にもいろいろクラス入ってるので試してみてね('-^*/
Javadocもあるんだけど、なんかメモとか混入してるからほしい人がいればってことで……(゜▽、゜

posted by すふぃあ at 15:22| Comment(1) | TrackBack(0) | 雁字

2012年03月25日

DoCoMoのアプリ落ちすぎ

SPモードなメールを見るようになってからだと思うんだけど、なんかすごくDoCoMoのアプリが落ちる。
とりあえず、スタックトレースを2個拾ってみた。
ATOKの時は発生率低かったけど、こっちは簡単に起きるね(笑)

最初のやつは、黙って裏で吐いてるエラー(普通に使ってる人には見えない)。
2番目のは、強制終了したとかメッセージが出てくる。
バグレポートも送れないし、プリインストールするならもっとちゃんとしたの作ってほしいな。
2個目のは、DoCoMoじゃないのかな?

03-25 22:58:06.861: E/DatabaseUtils(32600): Writing exception to parcel
03-25 22:58:06.861: E/DatabaseUtils(32600): android.database.sqlite.SQLiteAbortException: unavailable to link the app during the startup process.
03-25 22:58:06.861: E/DatabaseUtils(32600): at jp.co.nttdocomo.carriermail.service.AppLinkProvider.h(AppLinkProvider.java:157)
03-25 22:58:06.861: E/DatabaseUtils(32600): at jp.co.nttdocomo.carriermail.service.AppLinkProvider.query(AppLinkProvider.java:371)
03-25 22:58:06.861: E/DatabaseUtils(32600): at android.content.ContentProvider$Transport.bulkQuery(ContentProvider.java:174)
03-25 22:58:06.861: E/DatabaseUtils(32600): at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:111)
03-25 22:58:06.861: E/DatabaseUtils(32600): at android.os.Binder.execTransact(Binder.java:324)
03-25 22:58:06.861: E/DatabaseUtils(32600): at dalvik.system.NativeStart.run(Native Method)
03-25 22:58:09.351: E/AndroidRuntime(32621): FATAL EXCEPTION: main
03-25 22:58:09.351: E/AndroidRuntime(32621): android.database.sqlite.SQLiteException: unable to close due to unfinalised statements
03-25 22:58:09.351: E/AndroidRuntime(32621): at android.database.sqlite.SQLiteDatabase.dbclose(Native Method)
03-25 22:58:09.351: E/AndroidRuntime(32621): at android.database.sqlite.SQLiteDatabase.onAllReferencesReleased(SQLiteDatabase.java:327)
03-25 22:58:09.351: E/AndroidRuntime(32621): at android.database.sqlite.SQLiteDatabase.close(SQLiteDatabase.java:892)
03-25 22:58:09.351: E/AndroidRuntime(32621): at android.database.sqlite.SQLiteOpenHelper.close(SQLiteOpenHelper.java:220)
03-25 22:58:09.351: E/AndroidRuntime(32621): at jp.co.omronsoft.android.decoemojimanager_docomo.DBManager.close(DBManager.java:224)
03-25 22:58:09.351: E/AndroidRuntime(32621): at jp.co.omronsoft.android.decoemojimanager_docomo.DecoEmojiManager$1.handleMessage(DecoEmojiManager.java:159)
03-25 22:58:09.351: E/AndroidRuntime(32621): at android.os.Handler.dispatchMessage(Handler.java:99)
03-25 22:58:09.351: E/AndroidRuntime(32621): at android.os.Looper.loop(Looper.java:138)
03-25 22:58:09.351: E/AndroidRuntime(32621): at android.app.ActivityThread.main(ActivityThread.java:3701)
03-25 22:58:09.351: E/AndroidRuntime(32621): at java.lang.reflect.Method.invokeNative(Native Method)
03-25 22:58:09.351: E/AndroidRuntime(32621): at java.lang.reflect.Method.invoke(Method.java:507)
03-25 22:58:09.351: E/AndroidRuntime(32621): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
03-25 22:58:09.351: E/AndroidRuntime(32621): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)
03-25 22:58:09.351: E/AndroidRuntime(32621): at dalvik.system.NativeStart.main(Native Method)
posted by すふぃあ at 23:22| Comment(1) | TrackBack(0) | 雁字

2011年12月24日

LINQがわからない

この記事はAdvent Calendar 2011のC#の24日目……のおまけ編だよ。

Advent Calendarの他の人の記事でも解説はいろいろ出てきているけど、LINQがわからないんだよね。
と言うわけで、何がわからないのかを書いてみるよ。

わからないって言うのは、使いどころって言うか、どういうときに使うのかって言うか、そんな感じ。
わたしの直感全開なので意味不明になると思うけど、いつものことなので気にしない。

とにかく使えばいいじゃんって話なのかもだけど、
よくわからないでとりあえずよさそうだから使うって言うのはどうかと思うの。
最初はそれでも、ちゃんと理解した方が良いよね。

で、LINQって調べてると、SQLっぽいのがいっぱい出てくるんだよね。
SQLってDBとかになれてる人が見るとわかりやすいのかもしれないけど、
クライアントのアプリ作ってるとDBってあまり使わない気がするの。
だから、クエリ構文?で解説されてもよくわからない……。

この記事を書くのに、メソッド構文?を中心に書いてあるneue ccさんの記事から
いくつかサイト巡ってたら、この辺にパイプライン型とかの図があってわかりやすかった。

で、
「LINQってデータコレクションを、好きなパイプラインを使ってフィルターしてくれるってことかなー」
って思うところまで来たんだけど、それで良いのかがわからない(・x・

……これを書いてる間に少しわかってきた気がするから、少し使ってみようかな?
posted by すふぃあ at 00:45| Comment(1) | TrackBack(0) | 雁字

Windows PhoneでVNC Viewerつくってみたよ

☆前書き☆

この記事はAdvent Calendar 2011のC#の24日目だよ。

去年のAdvent Calendarとかみんな凄いの書いてるから、
わたしなんか書いて良いのかな〜って思ったりもしたんだけど、
相談したら書いて良いんじゃない?って言われたので書くことにしたの。

他の人に比べて内容も読みやすさもレベルを下げてお届け!
読みにくいって思ったら、この日の記事はなかったことにして次に期待すると良いとおもいまーす。
あ、C#のコアな話を期待している人、そんな内容はないからね!

と、前書きはこのくらいにしてすすむね。
この1ヶ月くらいで作ったWindows Phoneアプリあたりの話をだらだら書くよ。

☆作ったWindows Phoneアプリの紹介☆

C#の勉強ついでにいろいろアプリ作ってみてるんだけど、
Windows Phoneを手に入れたので、せっかくだから何かつくろーって。
で、Androidで作った「ラティ」ってアプリのWindows Phone版を作ることにしたの。
VNCとかRDPとかの、いわゆるリモートデスクトップって言うののクライアントアプリだよ。

なんか、最初に作るならHello Worldでしょ!って言うのが普通なのかもしれないけど、
見た目さみしいし、やっぱりきれいで動くのがいいじゃん?

Android版はVNCベースじゃなかったから、今回は、VNCにちゃんとつながるようにしよう!
というわけでWindows Phone版の「ラティ」はTightVNCのServerとかにつながるようになってるよ。
有料のカテゴリ?になってるけど、トライアル版でも機能差は無いので普通に無料で使えるよ。

☆RFBプロトコル編☆

VNCって言うのはRFBプロトコルで通信するので、それを実装したライブラリとかがないと、だよね。
ってことで探したんだけど……、使えそうなのがないっ(・x・

というわけでRFBプロトコルの仕様書日本語)を読むところから始めることに。
リモートデスクトップのプロトコルって読み解くの大変なんじゃないのかなぁ。
な〜んて最初は思って読んでみたんだけど、これが意外に凄い簡単なの。
FTPのプロトコル日本語)よりも簡単簡単。たぶん。

最初はなんか文字列の送受信するだけで、あとは、
位置+サイズ+画像のデータをひたすら受け取るだけだよ。ほら簡単。

いろいろ手抜き感はあるけど、実装したライブラリがあるので後でリンク張るね。
ここでは簡単に使い方を紹介するよ。

基本的なプロトコルの実装は、RFBStreamって言うのがあるから、それを使えばおっけ。
でもほら、接続から一連のパスワード確認とかは、まとめてやった方が楽じゃない?
というわけでRFBClientってクラスもあるよ。
でもでも、それでももっと簡単に使いたいって人のために、EmprssiaRFBClientって言うのも用意してみた〜。
今回はこれの紹介ってことで。

えーっと、ラティから抜粋したコードをブログ用に書き換えてるので動作保証はないでーす。
あ、もちろん、書き換えて無くても動作保証はないけど。

コーディングスタイルがあり得ない!って言うのはスルーするけど、
LINQとかRxとかAsyncはぜ〜んぜん使えてないのだ。
せっかくAsync CTP入れたのにね!(謎)

this.RFBClient = new EmpressiaRFBClient();
int[] encodings = new int[] { EncodingType.tight, EncodingType.ZRLE, EncodingType.zlib, EncodingType.zlibhex, EncodingType.CoRRE, EncodingType.RRE, EncodingType.Raw, EncodingType.Hextile, EncodingType.Cursor };

// 1.セットアップでいろいろ準備。
this.RFBClient.setup(
// 1−1.使う通信方式(エンコーディング)の設定。
encodings,
// 1−2.カーソルをクライアントで描画する。
(PixelFormat, x, y, width, height, pixelBytes, maskBytes) => {
}
// 1−3.EncodingType.CopyRectを使用する場合はもう一個引数増える。
);
this.RFBClient.ConnectFailed += (sender, e) => {
if(e.IsCanceled) {
return;
}
string message = null;
if(e.SecurityResult != null) {
if(e.SecurityResult.FailedReason != null) {
message = e.SecurityResult.FailedReason;
}
}
if(message == null) {
if(e.UnexpectedException != null) {
message = e.UnexpectedException.Message;
} else {
message = "なんか接続に失敗したみたい。ごめんなさい。理由はよくわかんない。";
}
}
this.RaiseDisconnected(message);
};
this.RFBClient.SendFailed += (ex) => {
this.RaiseDisconnected(ex.Message);
};
this.RFBClient.ReceiveFailed += (ex) => {
this.RaiseDisconnected(ex.Message);
};
this.RFBClient.FrameBufferInitialized += (PixelFormat, width, height) => {
// 2.画面情報の初期化。
AutoResetEvent Lock = new AutoResetEvent(false);
this.Dispatcher.BeginInvoke((EmpressiaRFBClient.FrameBufferInitializedHandler)delegate {
// 2−1.Windows PhoneだとARGB32が楽。違う場合は要求を送信するよ。
PixelFormat ARGB32 = new PixelFormat() {
BitsPerPixel = 32,
Depth = 24,
BigEndianFlag = 0,
TrueColourFlag = 1,
RedMax = 255,
GreenMax = 255,
BlueMax = 255,
RedShift = 16,
GreenShift = 8,
BlueShift = 0,
Padding1 = 0,
Padding2 = 0,
Padding3 = 0,
};
if(PixelFormat.Equals(ARGB32) == false) {
this.RFBClient.sendSetPixelFormat(ARGB32);
}
this.Image = new WriteableBitmap(this.RFBClient.FrameBufferWidth, this.RFBClient.FrameBufferHeight);
Lock.Set();
}, PixelFormat, width, height);
Lock.WaitOne();
};
this.RFBClient.MessageReceivingStarted += () => {
// 3.初回だけリクエストのタイミングを決める。2回目以降は勝手に呼ばれる。
this.RFBClient.sendFramebufferUpdateRequest(true, 0, 0, this.RFBClient.FrameBufferWidth, this.RFBClient.FrameBufferHeight);
};
this.RFBClient.ImageReceived += (s, rects) => {
lock(this.ImageEventLock) {
this.ImageLock.Reset();
this.Dispatcher.BeginInvoke((EmpressiaRFBClient.ImageReceivedHandler)delegate {
foreach(RFBRectangle rect in rects) {
// 4.透明なのを塗りつぶすよ。
for(int i = 3; i < rect.PixelBytes.Length; i += 4) {
rect.PixelBytes[i] = 0xFF;
}
for(int lineIndex = 0; lineIndex < rect.Height; ++lineIndex) {
Buffer.BlockCopy(rect.PixelBytes, lineIndex * rect.Stride, this.Image.Pixels, (rect.Y + lineIndex) * this.Image.PixelWidth * 4 + rect.X * 4, rect.Stride);
}
}
this.Image.Invalidate();
this.ImageLock.Set();
}, s, rects);
this.ImageLock.WaitOne();
}
};

this.RFBClient.connectAsync(Host, Port, Password);

重要そうなところは1〜4の番号を振ってコメント入れておいたっ。
1−2と1−3:
特殊な画像処理が必要なところ(クライアントの描画環境によるからRFBの範囲ではどうしようもない)。
2−1:
Windows PhoneのWriteableBitmapがARGB32(BGRA32?)だから楽するための処理ね。
わたしの作ったライブラリの一部がそれ前提なところが残ってる気もするし。
3:
コメント書いてて、これライブラリとしてダメじゃないカナーとか思った!
思ったけど今はこうなってるからいいよね(゚ー゚)(。_。)(゚-゚)(。_。)ウンウン
4:
RFBプロトコルは、透明度扱わないんだけど、
WriteableBitmapのARGB32だとアルファチャンネルってことになっちゃうから、
全部透過なしに上書きしてる。

あとは、xaml側と調整すれば画面が出るはず〜。
キー送信とか、マウスの操作は、
sendKeyEventとsendPointerEventっていうメソッドがあるから画面の操作と連携させればおっけ〜。
KeyEventは結構大変だけどねっ。マウス操作くらいならすぐすぐ。

是非試してみてね(  ̄▽ ̄)ノ

☆SSHプロトコル編☆

RFBプロトコルってパスワード部分をのぞけば暗号化されないから、
SSHでポートフォワードとかやりたいよね。
というか、Empressia Tunnelなんて作ってたから、
簡単にできるでしょ〜って思って、手を出してみたの。
まぁ、つまり大変でしたって話なんだけど……。

C#でSSHと言えば、SharpSSHとかが有名……だよね、
うん、わたしが知ってるくらいだから有名なの。
その、SharpSSH使おうと思ったんだけど、
これってJavaのJSchっていうライブラリの移植版みたいなんだよね。
元が結構古くて.NEtFramework1.1ベースみたい。

ってことで、ArrayListとかHashtableとかがWindows Phoneだと動かない。
Threadとかのメソッドも減って消えてるメソッドがあるからそのままじゃ使えないし。
BigIntegerもMono?のを使ってるみたいでこれがunsafeコードを持ってるんだよね。
結局、いろんなところ書き換えちゃった。

ほんとはそのまま動くようにするだけで良いんだろうけど、
元がJavaだからか、プロパティとかイベントとかがほとんど使われてなかったから、
めんどくさくて適当に書き換えちゃったところも。

RFBと同じでライブラリは最後にまとめて張るね。
まぁ、ポートフォワード付近しかタメしてなかったりするから、いろいろなところでエラーとか出るかも(笑)

あ、おまけでEmpressiaSSHなんてライブラリも作ったよ。
このライブラリを使うと、SECSH(ssh.com)形式の秘密鍵ファイルが使えるようになるの。
あと、ポートフォワードが簡単に使えるクラスEmpressiaSSHTunnelClientも用意してあるのでお試しアレ。
RFBみたいに使い方を紹介するよ。
もちろん動かなくても知らない!さすがわたし!無責任!

EmpressiaSSHTunnelClient SSHTunnelClient = new EmpressiaSSHTunnelClient();
userInfo.FingerprintConfirmationRequired += (string host, string type, string fingerprint) => {
return true;
};
userInfo.ChangedFingerprintConfirmationRequired += (string host, string type, string fingerprint) => {
return true;
};
SSHTunnelClient.Connected += delegate {
// 接続したよ。
};
SSHTunnelClient.Bound += delegate {
// ポートフォワードが開始されたよ。
};
SSHTunnelClient.ConnectionFailed += delegate {
// 接続に失敗したよ。
};
SSHTunnelClient.Disconnected += delegate {
// 切断されたよ。
};
SSHTunnelClient.Unbound += delegate {
// ポートフォワードが終わったよ。
};
EmpressiaUserInfo userInfo = new EmpressiaUserInfo("sshpassword");
SSHTunnelClient.connectAsync(new TransferProfile() {
TunnelHost = "example.com",
TunnelPort = 22,
TunnelUser = "sshuser",
TunnelPassword = "sshpassword",
LocalHost = "127.0.0.1",
LocalPort = 5900,
RemoteHost = "192.168.0.2",
RemotePort = 5900,
}, userInfo, null);
なんか、パスワード2回指定してるけど気にしない!

でもさ、結局、Windows PhoneってSocketのAcceptできないんだよね。
というわけでローカルポートにバインドできなくて今回はあきらめたっ_(__)ノ彡☆

あ、あと、SilverlightとWindows Phoneだと、SshShellのコンソールリダイレクトが使えないはず。
Console.OpenStandardInput()とConsole.OpenStandardOutput()をどうすればいいのかがわからなくて……。

☆基本ライブラリ編☆

SSHとかRFBをWindows Phoneで作る時に思ったんだけど、
Windows Phoneって結構標準のクラスライブラリが削られてて面倒なんだよね。
暗号系はBouncy Castleあたりがあれば良いんだけど、ネットワーク関連がどうしようもなくて……。
ってことで、NetworkStreamとか作ってみてるよ。
パフォーマンスは微妙だと思うけど、だいたい同じ感じで使えるはず……。

あと、リングバッファなByteQueueとか、
それをストリームで扱うEndlessStreamなんかもあるので良ければドーゾ。

EmpressiaLibrary.dllにまとめて入れてあるので興味があれば〜。
ライブラリはまたまた最後にまとめて張っておくね。

使い方は、別に特殊なのはないので省略ね。
……みんなはこういうのどうしてるんだろう……?(・_・?)ハテ

☆その他ライブラリ編☆

RFBやってると、ZlibなStreamを延々読み続けないといけないんだよね。
ただ1個のストリーム読むだけなら良いんだけど、
飛び飛びにあるピクセルデータ部分だけを連続したZlibなStreamとして扱わないとダメって感じ。
標準クラスライブラリのDeflateStreamを使ってる分には問題ないんだけど、
DotNetZipのDeflateStreamだと、これがうまく動かないっ。
というわけでこれも書き換えてみたよ。
まぁ、使う機会はほとんどないと思うけど、後で張っておくね!

Bouncy CastleもWindows Phoneで動くように書き換えたのでこれも張っておくよ。

☆ライブラリまとめ☆

ず〜っとライブラリの話書いてきたけど、下に関連してる図を載せておくね。
EmpressiaLibraryDependencyGraph_20111224.png
であとは、ライブラリ達でーす。

えっと、Silverlight版は、プロジェクトファイル用意するだけなんだけど、
わたしが使う予定がないので用意してなかったり!

動かないじゃんっていうのがあれば、再現できるサンプルとかあればがんばるよ!たぶん(・x・

☆余談☆

ところで、Vita用のSDKが来ないんだけど……。
って書こうと思ったら、昨日(23日)の15時頃に連絡があったよ。
やっと、開発環境周りの日本語訳ができたのかな〜。
というわけでPS Suite SDKダウンロードしてみた。
まだ何も作ってないけど、なんか作りにくそうだった……(・x・

タグ:Windows Phone
posted by すふぃあ at 00:34| Comment(4) | TrackBack(1) | 雁字

2011年12月08日

Windows Phone 7で暗号化

えっと、なんか、WP7の暗号化っていろいろ足りなかったりするよね。

たぶん、Phone7.FxとかBouncy Castleとかいろいろあるから、
何でも使えば良いんだと想うんだけど、

#wp7dev_jpで困っている人がいるみたいだったので、
とりあえず、Bouncy CastleをWP7で動くようにビルドしたのをおいてみたよ('-^*/

もちろん、ライセンスは、元の方を見て使ってね。
http://www.bouncycastle.org/
一応ビルドしたのはここね(゜▽、゜
http://www.empressia.jp/dll/BouncyCastle.Empressia.WindowsPhone.dll

こういうのはダメなんだよ!ってことはないとおもってるけど、
そういう情報があったら教えてね。速攻消すから。
あと、WP7で使っておかしくなっても、元の方に文句言わないでね。
タグ:Windows Phone
posted by すふぃあ at 23:09| Comment(1) | TrackBack(0) | 雁字

2011年10月30日

Windows PhoneのISEToolのGUIアプリ

Windows Phone OS 7.1 あたりで出てきたISEToolがCUIなので、
GUIで操作できるアプリを作ってみたよ。一通り必要な機能は入れたつもり。
この辺からダウンロードできるよ

リモートの表示がちょっと遅いんだよねぇ。階層が深ければ深いほど。
必要なときに読み込むようにしてあげた方が良いのかなぁ。
タグ:Windows Phone
posted by すふぃあ at 15:13| Comment(3) | TrackBack(0) | 雁字

2011年09月03日

MMDX(SlimDX版)のモデルロードを高速化

何となくぼーっと、MMDXを触ってみているよ。


Lat式ミクVer2.3を歩かせてみてるんだけど、ロード時間が長いので、ライブラリの速度アップをしてみました。


ここのリンクからダウンロードできるよ。


わたしのPC上でだけど、Lat式ミクVer2.3のロード時間が12秒→3秒くらいになた(゜▽、゜快適
タグ:MMD MMDX
posted by すふぃあ at 01:08| Comment(1) | TrackBack(0) | 雁字