Proximity APIでWi-Fi Direct通信

WinRT APIは、Proximity APIを通じてWi-Fi Direct通信を行えます。通常のWi-Fiは、アクセスポイントを通じてインターネットにつながったデバイスの間で通信が可能ですが、アクセスポイントが無ければデバイス間で通信はできません。Wi-Fi Directは、アクセスポイントが無くても、サポートしているデバイス間でP2Pで接続し、データ通信を可能にする技術です。ハードウェアは通常のWi-Fiと同じものが使えます。アクセスポイントを介さずにつなげられるので、データ漏えいの危険も減ります。考えてみれば、単にデータを交換したいだけならば、インターネットに接続する必要はないわけです。近場にいる人とのショートメッセージやイメージデータの交換ができるので、ローカルSNSや近場のマルチユーザーゲームなど、アイデア次第で様々な応用が考えられます。

https://www.wi-fi.org/discover-and-learn/wi-fi-direct を見ると、Wi-Fi Directはデータ転送が250Mbpsとかなり高速、ハードウェアは従来のWi-Fiそのままが使える、通信に関するセキュリティ、アクセスポイントとの併用など、かなりいい感じです。これを活用しない手はありません。しかし、現時点ではすべてのWindows 8 PCがWi-Fi Directをサポートしているわけではないので、ご注意。ま、持ってる者同士でつながってください。

使い方を以下に説明していきます。Wi-Fi Directは、Windows.Networking.Proximity名前空間のPeerFinderクラスを使います。最初に、アプリが動作しているPCでWi-Fi Directが使えるかをチェックします。PeerFinderクラスのSupportedDiscoveryTypesプロパティをチェックします。

        if ((PeerFinder.SupportedDiscoveryTypes & PeerDiscoveryTypes.Browse) == PeerDiscoveryTypes.Browse)

このプロパティは、ビットフラグなので、上の様なチェックをします。この条件がtrueであれば、Wi-Fi Directを利用可能です。falseの場合には、「Wi-Fi Direct機能付きのPCを購入してね」といったメッセージを出しましょうw。

Wi-Fi Directで接続するためには、別のPCからブラウズできるようにしておく必要があります。

               PeerFinder.ConnectionRequested +=
                   new TypedEventHandler<object, ConnectionRequestedEventArgs>
                       (PeerFinder_ConnectionRequested);
               PeerFinder.Start();

Start()をコールすると、同じストアアプリがフロントで動いているPC上で、探すことができるようになります。ConnectionRequestedイベントは、別のPCからの接続要求を受け付けるためのものです。

同じストアアプリが動いていて、Start()メソッドをコール済みのPCを探すには、

            var peers = await PeerFinder.FindAllPeersAsync();
            foreach (var peer in peers)
            {

と、FindAllPeersAsync()を使います。peersは、PeerInformationというクラスのインスタンスのリストです。DisplayNameプロパティで相手のデバイスの名前が判ります。

Wi-Fi Directで接続する場合、

                var streamSocket = await PeerFinder.ConnectAsync(peer);

と、ConnectAsync()をコールします。接続が完了すると、通信するためのストリームソケットを取得できます。
ストリームソケットを取得で来たら、データの受信待ちを開始します。streamSocketからデータ送受信の為のReaderとWriterを作成します。

            peerWriter = new DataWriter(streamSocket.OutputStream);
            peerReader = new DataReader(streamSocket.InputStream);

peerWriterとpeerReaderは、別の目的でも使用するのでクラスのメンバー変数として定義しておきましょう。ストリームソケットを基にDataRearインスタンスを作成したら、あとは、LoadAsyncやReadXXXメソッドを使ってデータを受信し続けます。データの送受信については、別の投稿で詳しく解説する予定ですのでそちらを参照してください。

別のPCがFindAllPeersAsync()メソッドで発見し、ConnectAsync()メソッドをコールして接続要求をすると、先ほど紹介したようにConnectionRequestedイベントに登録したハンドラがコールされます。この要求を受け付ける場合、

            var streamSocket = await PeerFinder.ConnectAsync(e.PeerInformation);

と、ConnectAsync()メソッドをコールします。ConnectionRequestedイベントハンドラの引数のPeerInformationプロパティに接続要求を出したPeerの情報が入っています。ConnectAsync()メソッドをコールして得られたストリームソケットを使ってデータの送受信を行うわけです。AcceptAsync()メソッドをコールしなかった場合はWi-Fi Direct接続要求は無視され、タイムアウト処理されます。Start、FindAllPeersAsync、ConnectAsync、AcceptAsyncのすべてのメソッドコールで、try、catchで例外を捕捉して適切な処理をすることを忘れずに。

以上の流れを図に示しておきますね。

DataReaderインスタンスの作成、LoadAsync、ReadXXXメソッドによるデータ受信で一つ注意をしておきます。この一連の流れの中で通信にかかわる以外のawaitをつけたコール(メッセージダイアログやUIの表示を直接更新するようなDispatcherへ委譲など)は実行しないでください。これをやると、折角接続できたPeerとの通信が切断されてしまうという現象が起こるようです。

次のポストでは、データの送受信について解説します。お楽しみに。