Socket マルチキャスト通信 - Windows Phone編

Windows Phone 7でのSocketマルチキャスト通信の使い方を説明します。

スマートフォンは基本各人がそれぞれのデバイスを持っていますよね。各人が各人の端末を操作して、各端末から発せられるデータを共有したい場面、結構、あると思うのですよ。例えばセミナーでのジャンケン大会とか、投票とか、フィーリングカップル5対5とか、カードゲームとか、合コン席決めとか(パーティ系か)。”FacebookとかTwitter、その他のクラウドサービス使えば良いじゃん”という声が聞こえてきそうですが、キャリアの通信トラフィックを増やすのもなんだし、当然通信の遅延も発生するし、…で、Wi-FiでLANに接続できる環境であれば、Socketマルチキャスト通信という選択も、そんなに悪くないかなと。3人以上で1つの端末に顔寄せ合って、操作するのもねぇ…

Windows Phone 7では、UdpAnySourceMulticastClientというクラスが用意されていて、Multicast通信を簡単にアプリに組み込むことが出来ます。

このクラスはSystem.Net.dllコンポーネントに入っていて、System.Net.Sockets名前空間に属するものです。

            UdpAnySourceMulticastClient myClient = new UdpAnySourceMulticastClient(groupAddress, groupPort);
            try
            {
                myClient.BeginJoinGroup(
                    result =>
                    {
                        try
                        {
                            myClient.EndJoinGroup(result);
                            myClient.MulticastLoopback = true;
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("Join succeeded. but something wrong. " + ex.Message);
                        }
                    }, null
                );
            }
            catch (Exception ex)
            {
                MessageBox.Show("Join failed. " + ex.Message);
            }

 こんな風にコードを書けば、グループへのJoinが可能です。コンストラクターに渡されている2つの引数は、JoinしたいグループのIPAddressと、ポート番号です。直ぐにこの機能を試してみたい方は、https://msdn.microsoft.com/en-us/library/hh286407(v=VS.92).aspx で公開されているWalkthroughとSampleで試してみてください。PCを2台用意して、それぞれのPCでVisual Studioを起動してEmulator実行するか、1台のPCでEmulator実行し、実端末にアプリを仕込んで動かせば通信している様を確かめることが出来ます。

UdpAnySourceMulticastClient はSilverlight for Windows Phone向けのライブラリであり、他のクラス群がそうであるように、非同期プログラミングモデルであることに注意してください。上のコードでは、BeginJoinGroupメソッドをコールし、Join処理が終わったところで、result => {...}のブロックが実行されます。
グループへのJoin後は、送信であれば、

            byte[] msg = Encoding.UTF8.GetBytes(stringText));
            myClient.BeginSendToGroup(msg, 0, msg.Length,
                result =>
                {
                    myClient.EndSendToGroup(result);
                    …
                }, null
            );

こちらも非同期。受信は、receiveBufferを受信用のbyte[]型の配列として、

        private void Receive()
        {
                myClient.BeginReceiveFromGroup(receiveBuffer, 0, receiveBuffer.Length,
                    result =>
                    {
                        try
                        {
                            IPEndPoint source;
                            myClient.EndReceiveFromGroup(result, out source);
                            string dataReceived = Encoding.UTF8.GetString(receiveBuffer, 0, receiveBuffer.Length).TrimEnd(new char[] { '\0' });
                            string sourceIPAddress = source.Address.ToString();
                            …
                            Receive()

 と、こちらも非同期的に受信を開始して、EndReceiveFromGroupをコールして送信者情報を取得すると。受信データはreceiveBuffer二格納されているので、それを処理し、再度Receive()メソッドをコールし受信待機、という流れになります。一見再帰コールに見えますが、非同期に動いていくので大丈夫です。

後は、送受信するデータの意味づけ、構造を規定してやればOKです。

この機能と、Motionセンサーを使ったサンプルアプリを作って、https://wpwfsjkp.codeplex.com/ で公開しているので、試してみてください。複数端末でジャンケンが出来るサンプルアプリです。Multicastグループ通信をよりアプリで使いやすくするライブラリーや、Motionセンサーからジェスチャー情報を取り出すライブラリーも合わせて公開しているので、参考にしてみてください。ジェスチャー情報を取り出すライブラリーは、別途説明しますね。公開されているアプリの名は、WiFi Jangken、マーケットプレースへの登録も目指します。

それから、このUdpAnySourceMulticastClient クラス、元々Silverlight向けに提供されているクラスなので、デスクトップ向けのOOB(Out of Browser)アプリでも全く同じコードで、グループへのJoin、データの送受信ができます。色々考えているとPCとかともつなぎたくなるものです。