読者です 読者をやめる 読者になる 読者になる

.NET で WebSocket 使うなら WCF WebSockets で FA

WCF WebSockets で WebSocket クライアントが提供されていることを今さら知りました。WebSocket サーバーが提供されていることは前から知っていたんですけどね。ここのところずっと RubyJavaScript でばかり遊んでいたので、.NET の情報にだいぶ疎くなっていました。

ちょうど WebSocket について調べていたので、せっかくだし WCF WebSockets 試してみましょうかね。お題は、WebSocket のサンプルとしては定番の、なんちゃってチャットアプリで。久しぶりに C# を書く気がする。

WCF WebSockets は下記のサイトから入手できます。

インストールしたら、いざスタート。

まずは、サーバーから作成します。Visual Studio 2010 でコンソールプロジェクトを作成して、System.ServiceModel.dll と Microsoft.ServiceModel.WebSockets.dll を参照に追加し、次のコードを書きます。

using System;
using System.Collections.Generic;
using System.ServiceModel;
using Microsoft.ServiceModel.WebSockets;

namespace WebSocketSample.Server
{
    class Program
    {
        static void Main(string[] args)
        {
            // WebSocket のサービスをホストするには、
            // 専用の WebSocketHost クラスを使う
            var host = new WebSocketsHost<ChatService>(
                new Uri("ws://localhost:1234/chat"));

            // WebSocket 用のエンドポイントを登録
            host.AddWebSocketsEndpoint();
            
            // サービス開始
            host.Open();

            Console.WriteLine("Enter で終了します。");
            Console.ReadLine();

            host.Close();
        }
    }

    // セッションごとにサービスインスタンスを生成
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
        ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class ChatService : WebSocketsService
    {
        // チャットサーバーに接続しているセッションを格納
        private static readonly List<ChatService> _services = new List<ChatService>();

        public override void OnOpen()
        {
            _services.Add(this);
        }

        protected override void OnClose(object sender, EventArgs e)
        {
            _services.Remove(this);
        }

        public override void OnMessage(string value)
        {
            foreach (var service in _services)
            {
                service.SendMessage(value);
            }
        }
    }
}

サーバー側はたったこれだけ。OnMessage(string) ではなく OnMessage(byte[]) を間違ってオーバーライドすると、SendMessage(string) で送られてくるデータを受信できないので注意。私は見事ハマりました。

次にクライアントを作成します。こちらもコンソールプロジェクトとして作成し、Microsoft.ServiceModel.WebSockets.DesktopClient.dll を参照に追加します。クライアントのコードは次の通り。

using System;
using System.ServiceModel.WebSockets;

namespace WebSocketSample.Client
{
    class Program
    {
        static void Main(string[] args)
        {
            // WebSocket クライアント生成
            var client = new WebSocket("ws://localhost:1234/chat");

            // WebSocket サーバーからメッセージが送られてきたら
            // コンソールに表示
            client.OnData += (sender, e) =>
            {
                Console.WriteLine("from server: " + e.TextData);
            };

            // WebSocket サーバーに接続
            client.Open();

            while (true)
            {
                var message = Console.ReadLine();

                // 入力されたメッセージをサーバーに送信
                client.SendMessage(message);
            }
        }
    }
}

WebSocket クライアントの API は、HTML5 の WebSocket API に似ているので、調べなくても使えました。これでサーバーとクライアントの完成です。

サーバーとクライアント(2つ)を起動し、それぞれのクライアントでメッセージを入力すると、
f:id:griefworker:20120217192803p:image
ちゃんと WebSocket でサーバー側からプッシュされています。簡単に WebSocket でチャットアプリが書けてしまいましたよ。Microsoft++。