つくるよ

つくらないかも

SuperWebSocket

C#でWebSocketサーバーをやってみる その3

■UbuntuにMonoをインストールする
Ubuntu上にMonoをインストールし、C#のプログラムを実行できるようにします。
使用しているバージョンは10.04です。(ちなみに、さくらインターネットのVPSを利用しています)
今回はaptを使って楽にインストールしましたが、最新バージョンを利用する為には少し設定を変更する必要があります。
それについては以下の記事を参考させていただきました。

Ubuntu 10.04 で Mono 2.63 を使う - Schimaの日記

細かいところは省略しましたが、MonoさえインストールできればUbuntu側の設定は完了です。

■サンプルプログラムを実行する
前回、Windowsでビルドした実行ファイルをそのまま使用することができます。
適当なディレクトリに配置し、以下のようなコマンドを叩けば実行できます。
mono 実行ファイル名.exe

余談ですが、僕が試した環境では実行ファイルに実行権限があればファイル名を叩くだけで実行することも出来ました。

後は前回と同じようにクライアントからアクセスすればOKです。
必要な場合は、クライアント側のURLを書き換える事を忘れないようにします。

が、しかし、ここでいくつかのブラウザでは問題が発生すると思います。
僕が確認した限りでは、WindowsのChrome16とiPad(IOS4)のSafariで正常に通信を行うことが出来ません。

■通信できない原因
SuperWebSocketで通信を行う際、クライアントへのレスポンスに含まれる改行コードは、実行環境依存になっています。(バージョン0.1と0.2で確認)
WindowsであればCRLF、LinuxであればLFです。Macは確認していません。
そして、上述のブラウザは改行コードがLFのレスポンスを受け付けないようになっているため、通信に失敗するようです。
あいにく、SuperWebSocketとブラウザとどちらの実装が不味いのか、明確な情報を探し当てることができませんでした。
どちらにせよブラウザ側を修正することはできないので、今回はSuperWebSocketのソースを改変することで対応しました。

■SuperWebSocketを改変する
まずは、今まで使用していたバージョン0.1ではなく、最新のバージョン0.2(2012/2/3現在)をダウンロードしなおしました。

修正対象のソースは、SuperWebSocket\Protocol ディレクトリ内にある以下の2つのファイルです
・DraftHybi00Processor.cs
・DraftHybi10Processor.cs

どちらも、Handshakeメソッド内でレスポンスを送信している箇所を修正します。
レスポンスはStringBuilderのAppenLineメソッドを使って作られていますが、このとき使われる改行文字はEnvironment.NewLineです。
これを常にCRLFで改行されるように置き換えます。

修正前
session.SocketSession.SendResponse(responseBuilder.ToString());


修正後
session.SocketSession.SendResponse(responseBuilder.ToString().Replace(Environment.NewLine, "\r\n"));


最後に、SuperWebSocket.csprojをビルドしてSuperWebSocket.dllを作成し、サンプルプログラム内のdllと置き換えます。
これで先ほど失敗したブラウザとも正常に通信できるようになります。

■まとめ
以上で当初予定していた目標を達成できました。
しかしながら、必要最低限の機能しか使用していませんし、パフォーマンス等を含めた実用性に関しても未知数です。
今後も何か発見があれば記事をまとめてみようと思います。

C#でWebSocketサーバーをやってみる その2

※2012/1/29追記
C#サンプルコードの参照アセンブリに漏れがありましたので追記しました。

■前回の補足
前回、いくつか大事なことを記載していなかったので、最初に補足しておきます。

諸々のバージョン
・Mono 2.10.8
・MonoDevelop 2.8.5.1
・SuperWebSocket 0.1
・C# 4.0

・MonoDevelopの設定
メニューの「ツール」→「Options」から以下の2つの設定を変更します。 MonoDevelop01
MonoDevelop02

■SuperWebSocketとは
さて本題ですが、まずは今回使用するSuperWebSocketについて軽く触れておきます。
SuperWebSocketは、SuperSocketというソケット通信用フレームワークを使用して作られたライブラリです。
現在、SuperWebSocketには十分なドキュメントが存在していませんが、SuperSocketのドキュメントを読めば概要は掴めそうな感じです。ちゃんと読んでませんが。
とは言っても、いくつかイベントを書いていけば通信できてしまうので、.NETに慣れ親しんでいる人ならさほど苦労せず使えると思います。
また、log4netによるログ出力にも対応しているようです。

余談ですが、.NET用のWebSocketサーバーは他にもWCF WebSocketsなどがあります。
WCF WebSocketsはWCFの勉強がてら使ってみたかったのですが、Mono上で動かなかったので断念しました。
他にイケてるのを知ってる方がいたら教えてください。

■サーバー側のサンプルプログラムを作る
簡単な通信を行うプログラムを、コンソールアプリケーションとして作成します。
MonoDevelopでソリューションを作る方法などは割愛します。
また、参照アセンブリに以下のファイルを追加してください。

・SuperWebSocket.dll : SuperWebSocketをビルドして作成されたファイル
・SuperSocket.Common.dll : SuperWebSocketに同梱(Reference\SuperSocket\Net40)
・SuperSocket.SocketBase.dll : 同上
・SuperSocket.SocketEngine.dll : 同上
※2012/1/29追記
・Newtonsoft.Json.dll : Reference\Json.NET\Net40
・log4net.dll Reference

前置きが長くなりましたが、以下が実際のコードです。
重要な名前空間は省略せずに記述しました。
using System;
using SuperSocket.Common;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketEngine;
using SuperWebSocket;

namespace SWSSample
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            //コンフィグオブジェクト作成
            var rootConfig = new SuperSocket.SocketBase.Config.RootConfig();
            var serverConfig = new SuperSocket.SocketBase.Config.ServerConfig()
            {
                Port = 2012,
                Ip = "Any",
                MaxConnectionNumber = 100,
                Mode = SuperSocket.SocketBase.SocketMode.Sync,
                Name = "SuperWebSocket Sample Server"
            };
                
            //サーバーオブジェクト作成&初期化
            var server = new SuperWebSocket.WebSocketServer();
            server.Setup(rootConfig, serverConfig,
                            SuperSocket.SocketEngine.SocketServerFactory.Instance);
            
            //イベントハンドラの設定
            //接続
            server.NewSessionConnected += HandleServerNewSessionConnected;
            //メッセージ受信
            server.NewMessageReceived += HandleServerNewMessageReceived;
            //切断        
            server.SessionClosed += HandleServerSessionClosed;
            
            //サーバー起動
            Console.WriteLine("Start!");
            server.Start();
        }
        
        //接続
        static void HandleServerNewSessionConnected(SuperWebSocket.WebSocketSession session)
        {
                Console.WriteLine("Connected!!");
            
                //メッセージ送信
                session.SendResponse("Hello!");
         }
        
        //メッセージ受信
        static void HandleServerNewMessageReceived (SuperWebSocket.WebSocketSession session,
                                                    string e)
        {
                Console.WriteLine("Received: " + e);
    
                //メッセージ送信
                session.SendResponse("[" + e + "]OK!");
        }
        
        //切断
        static void HandleServerSessionClosed (SuperWebSocket.WebSocketSession session,
                                                    SuperSocket.SocketBase.CloseReason e)
        {
                Console.WriteLine("Closed...");
            
                //サーバー終了
                session.AppServer.Stop();
        }
    }
}
コメントを見ていただければ何をやっているかわかると思います。
それ以外の要点を挙げるなら以下の3点くらい。

・サーバーの設定はconfigファイルで行うことも出来ます(この辺は次回以降に書くかも)
・イベントハンドラの引数として渡されるsessionオブジェクトはクライアントと1:1で紐付いています
・エラー処理は割愛(というかまだ調べてない)しているのでコードのコピペ利用等は自己責任でお願いします

■クライアント側のサンプルページを作る
続いてクライアント側のHTMLです。
Chrome 16と FireFox 9で動作確認しました。
<html>
    <body>
        <div id="main">
        </div>
    </body>

    <script type="text/javascript">
    
    var wsUrl = "ws://localhost:2012";    //WebSocketサーバーのURL
    var webSocket = null;                    //WebSocketオブジェクト
    
    var mainDiv = document.getElementById("main"); //結果表示用の要素
    
    //WebSocketオブジェクト作成
    if (typeof WebSocket != "undefined"){
        //Chromeで動作確認
        webSocket = new WebSocket(wsUrl);
    }
    else if (typeof MozWebSocket != "undefined"){
        //FireFoxで動作確認
        webSocket = new MozWebSocket(wsUrl);
    }
    else {
        mainDiv.innerHTML += "don't use WebSocket<br />";
    }
    
    //イベントハンドラの設定
    if (webSocket){
        
        //接続
        webSocket.onopen = function() {
            mainDiv.innerHTML += "onopen<br />";
            webSocket.send("Open!");
        };
        
        //メッセージ受信
        webSocket.onmessage = function(event) {
            mainDiv.innerHTML += "onmessage: " + event.data + "<br />";
        };
        
        //切断
        webSocket.onclose = function() {
            mainDiv.innerHTML += "onclose<br />";
        };
    }
    </script>
</html>
こちらも特に難しいことはしていません。

■動作確認
サーバーを起動した状態でクライアントページを開くと、接続とメッセージ送受信が行われます。
サーバーを終了するか、クライアントを閉じるかした時点でもう一方の切断処理が実行されます。

■まとめ
こうやって一連のコード書いてしまうと、簡単にWebSocketアプリケーションが作れそうな気がしてきますね。
ただ、非同期処理やエラー発生時にどうなるか検証していないのが怖いところではあります。

次回はこのプログラムをLinux上で動かしてみたいと思います。

C#でWebSocketサーバーをやってみる その1

■趣旨
WebSocketサーバーはnode.jsとかJettyとかでもできるけど、オラC#が好きだからC#でやるだ。
でもWebでサーバーサイドつったらLinuxがメジャーだし、ここは試しにMonoも使ってみっか。

■最終目標
サーバーサイド→Linux(Ubuntu) + Mono + C#
クライアントサイド→HTML + Javascript
で双方向通信する。

■方針
細かいところは気にせずとにかく進める。

■まずやること
まず開発環境の準備です。
最終的な動作環境はLinuxですが、当面はWindows上で作業します。

以下のサイトからMono(実行環境)とMonoDevelop(IDE)をダウンロードおよびインストールしましょう。

Mono
MonoDevelop

とは言うものの、Visual Studioがあればこいつらは要らないかもしれません。
少なくともConsole.Write()するだけの簡単なアセンブリは、VSでビルドしたものがLinux上でも動きました。
逆に、WindowsのMonoでは動くけどLinuxだとダメっていうパターンもあるかもしれませんが、ちゃんと調べてないのでよくわかりません。
でもまあMono用と銘打ってあるので使ってみます。

■次にやること
次にSuperWebSocketという.NETで実装されたWebSocketサーバーを準備します。
「やってみる」とは書いたけど「作ってみる」とは書いてないので使えるもんは使います。
RFCの仕様なんか読んでられっか。

SuperWebSocketは以下のサイトよりダウンロード
SuperWebSocket, a .NET WebSocket Server

解凍後、直下のフォルダにある「Build.bat」を実行すると、同階層のbinフォルダにアセンブリが作成されます。
自分でソリューション開いてビルドしても問題ないです。

■まとめ
以上で開発準備はひとまず完了です。
次回はサンプルプログラムの作成、次々回はLinux上の環境構築をまとめたいと思います。
QRコード
QRコード
Profile
  • ライブドアブログ