今更GKSessionのクライアント・サーバー型の挙動を検証してみた


## はじめに

とある事情で全世代のiPad端末（初代iPadからiPad Airまで）に対応したデータ通信機能（※ただしWi-Fi環境が有るとは限らないとする...）を実装する必要が出てきました。しかも１対１ではなく１対複数です。そこで初代iPad（iOS5.1.1）でも動作するGKSessionのクライアント・サーバー型の挙動を検証してみることにしました。

## GKSessionとは？
* デバイス間でのデータ通信（P2P）を簡単に実現する便利クラスです（GameKitの一部）。
* iOS7でMultipeer Connectivity Frameworkが登場したので（かどうかは判りませんが） __現在はGKSessionは非推奨__ です。
* Bluetooth/Wi-Fiどちらかを勝手に選択して使ってくれます。
* 昔の公式ドキュメントによれば、クライアント・サーバー型は最大16人まで同一セッションに入れる...らしいです。

## 検証について

事の発端は「16人も接続できるなんて凄いじゃんiPad！！」などと思って適当にテスト用のコードを組んでいる時、ふと「17人目がサーバーに接続しようとしたら、どういう挙動になるんだろう？接続に失敗するの？そもそもサーバーを検出できないの？」などと疑問に思った事でした。

早速iPadを20台ぐらい横に並べて一斉にサーバー(Bluetooth)に接続するテストコードを動かしたら...

**そもそも16人も接続できない事が判明** (5台目ぐらいから怪しい雰囲気に...)

ということで、iPad8台を使ってどんな挙動になるか簡単に実験してみました。

検証方法ですが、１台をサーバー（BluetoothまたはWi-Fiどちらか一方しか扱えない状態）にし、各クライアントはそのサーバーに接続しにいくだけという単純なプログラムを用意し、クライアントがどんな挙動になるかをまとめてみました。一回の実験で１分ぐらいは放置しました。

## 試した結果
|端末(OS)|iPad1(5.1.1)|iPad2(6.1.3)|iPad3(7.0.4)|iPad5(7.0.4)|iPad3(5.1.1)|iPad3(7.0.4)|iPad3(7.0.4)|iPad3(6.1.3)|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|1回目|OK|OK|サーバーBT|OK|OK|自動切断|自動切断|不参加|
|2回目|OK|OK|サーバーBT|自動切断|OK|OK|自動切断|不参加|
|3回目|OK|OK|サーバーBT|OK|OK|OK|OK|不参加|
|4回目|OK|OK|サーバーBT|OK|OK|OK|OK|不参加|
|5回目|OK|OK|サーバーBT|自動切断|OK|自動切断|自動切断|不参加|
|6回目|OK|サーバーBT|OK|サーバー未発見|OK|サーバー未発見|サーバー未発見|不参加|
|7回目|自動切断|サーバーBT|自動切断|自動切断|OK|タイムアウト|変なエラー|OK|
|8回目|OK|サーバーBT|OK|自動切断|OK|OK|接続要求まで|OK|
|9回目|OK|サーバーBT|OK|接続要求まで|OK|OK|OK|OK|
|10回目|接続要求まで|サーバーBT|OK|OK|OK|OK|自動切断|OK|
|11回目|OK|サーバーWF|自動切断|自動切断|OK|自動切断|自動切断|OK|
|12回目|OK|OK|サーバーWF|自動切断|OK|自動切断|自動切断|OK|
|13回目|OK|OK|サーバーWF|自動切断|OK|自動切断|自動切断|OK|
|14回目|不参加|不参加|サーバーWF|OK|不参加|OK|OK|不参加|

* `OK`が接続に成功し、しばらくしても自動切断されなかった端末です。
* `自動切断`は接続に成功しても、数秒／数十秒経って勝手に切断してしまった端末です。その際、サーバー側は切断を感知できていても、クライアント側は検知できていないケースがよく起きました。このケースに陥りますと、クライアント側でデータ送信や切断を実行した瞬間にアプリがフリーズしてしまいました。
* 「変なエラー」とは`Failed while pending outgoing invitation.`というエラーです。
* iPad Airで32bitバイナリを動作させると`Bluetooth problem in 32-bit processes on 64-bit system: skipping check`というログが出力されました（どんな問題が起きているのかは判りません）。

## 考察

* データ少ないですが、BluetoothでもWi-Fiでも接続の安定感には大差が無さそうです。
* 16人同時接続は無謀そうです。現実的な最大接続数は４プレイヤーかと思われます。
* iOS7の成績があまりよくないような気もしますし、電波の干渉も影響しているのかもしれませんが、定かではありません(^_^;

ちなみに、この検証のあと、stackoverflowで同じような事が書いてある記事を見つけました。
参考：http://stackoverflow.com/questions/11612732/iphone-p2p-is-gksession-unreliable-beyond-4-peers

回答者のGoogle翻訳:
>私はあなたを確保することができることはGKSessionは非常に不安定であり、これらのドキュメントを信頼してはならないことである。実際、 Appleは最近、完全に文書を削除することを決めた。
> 
>私は多くのテストを行なったし、私は実用的な限界が4接続されたデバイス（サーバや3クライアントなど1動作）であることを示唆している。もちろん、それはあなた自身のテストシナリオを実行することが良いでしょう。

>私はまた、 4つ以上のプレーヤーを可能にする任意のゲームを見つけることができませんでした。 8選手を可能にしたが、彼らはそれを削除することにした - 私は知っていたことだけは、Apple独自のテキサスホールデムた。

>そして少なくとも最後のではなく、ゲームセンターでは、 4選手の制限ピア·ツー·ピアにゲームを課している。

>はい、私は10選手をサポートする必要があり、ゲームを開発していますが、 4つ以上のデバイスが存在したとき、我々のテストでは、それが使用不能/不安定になった。不安定なことで私は意味：時々、分未満でのピアとの接続ドロップを見つけることができません。さらに悪いことに、 iOSの6へのアップデートメッセージを送信しようとしているときに（エラーなしスタックトレース、全く何もない）を凍結しないようないくつかの奇妙な行動をもたらした。その他奇妙なこと：プレーヤーが接続を失ったとき、他のすべてのプレイヤーが切断取得します。

>編集：その応答は多くのテストを行なったし、共有するためのより多くの情報を持っている。

>iOSの6を使用すると、私は、Wi-FiまたはBluetoothのいずれかを使用して9のデバイスと確実に遊ぶことができました。しかし大きな問題は、 STILあります：あなたは、デバイスのいずれかが、そのWi-Fi付きの場合は、一度に原因不明の凍結付きノースタックトレース時に直面するだろう原因はiOS 5を使用してデバイスとiOSの6を使用してデバイスを接続することはできません有効に。あなたはどちらのアプリでサポートされる最小バージョンとしてのiOS 6を設定したり、あなたはそれらのWi-Fiを無効にして、 Bluetoothを使用するようにユーザーに依頼する必要があります。


## おわりに

というわけで今回は残念な結果になってしまいました。
Multipeer Connectivity Frameworkは安定してくれていると良いですね！（あまり期待はしていませんが(^^;)）
またどなたか安定した通信方法を検証された方がいらっしゃいましたらコメントを頂けると幸いです。