ラベル websocket の投稿を表示しています。 すべての投稿を表示
ラベル websocket の投稿を表示しています。 すべての投稿を表示

2013/02/27

qemu VNC on WebSocket

はじめに

qemu 1.4 では Websocket プロトコル上で VNC を実現する機能が実装されました。
Qemu/Changelog/1.4
従来、ブラウザ(Websocket)でVNCを利用する場合、Websockify などを用いて、Websocket 通信を通常のソケット通信に変換しなければなりませんでした。今回 qemu VNC がWebsocket 対応したことにより、従来のような面倒な変換なしにブラウザ経由で VNC を利用できます。HTML5対応のブラウザであれば、Java プラグインなど無しに気軽に VNC を利用できるようになるのでとても便利です。

関連コミット:
http://git.qemu.org/?p=qemu.git;a=commit;h=7536ee4bc3da7e9b7fdadba5ba6ade63eaace430

使い方

qemu の configure 段階で vnc-ws を有効にします。
$ ./configure --enable-vnc-ws
以下のようなエラーがでるかもしれません。
ERROR
ERROR: User requested feature vnc-ws
ERROR: configure was not able to find it
ERROR
その時は、gnutls-devel パッケージをインストールします。
# yum install gnutls-devel
無事にインストールが済んだら、libvirt XML ファイルを編集しましょう。
コンパイルした qemu を使用するため、emulator タグで qemu の path を変更します。
また、qemu に "-vnc :1,websocket" オプションを渡すためのタグを追加します。ここで、"1:" はディスプレイポート番号です。"0:" だと既存のディスプレイと重なるかもしれないので、ずらしてあります。
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
...
  <devices>
    <emulator>/usr/local/bin/qemu-system-x86_64</emulator>
    ...
  </devices>
  <qemu:commandline>
    <qemu:arg value='-vnc'/>
    <qemu:arg value=':1,websocket'/>
  </qemu:commandline>
</domain>

仮想マシンを起動し、novnc.com にアクセスします。
noVNC.com は HTML5(Canvasなど) と Websocket で実装された、Web ベースの VNC クライアントです。 ブラウザは必ず HTML5 対応の新し目のブラウザを使いましょう。
右上の "Connect" ボタンをクリックし、
Host : 127.0.0.1
Port : 5701
を入力します。ポート番号は、上記で設定したディスプレイ番号に 5700 を足したものになります。今の場合だと、ディスプレイ番号 "1" + 5700 = 5701 です。
接続できると、こんな感じで、画面が表示されます。Chrome の中で Firefox を動かして見ました。

せっかくなので、iphone と Nexus 7 でも試して見ました。
Nexus 7


iphone



自宅の WiMAX環境では、iphone は重くて使い物になりませんでした。Nexus 7 もキーボードがいまいち使いにくかったです。

ともあれ、VNC on Websocket ではブラウザさえあれば、どこからでも VNC で画面転送できるのは便利です。家の仮想マシンを VPN 接続で iphone から操作する、なんてもこともできます。

余談

SPICE の HTML5 クライアントはないのかな?と思ったらありました。
HTML5 - SPICE
qemu が Spice on Websocket に対応していないので、 Websockify が必要です。

2010/11/12

Erlang + Websocket でCanvas共有

拙作のerlang_websocket_serverを用いて、Canvas共有をErlangに移植しました。
非同期メッセージパッシングというパラダイムのおかげで簡単に書けます。

こちらです!どんどん落書きしてください!
http://etsukata.com/erl/cvws.html
ChromeおよびSafariで動作確認しています。複数のウインドウを立ち上げて描いてみてください。

クライアントサイドのコードはNode.js版と全く一緒です。
サーバーサイドのコードを以下に掲載します。

githubでお読みになると、横スクロールがなくて見やすいです。
https://github.com/Etsukata/erlang_websocket_server/blob/master/example/canvas_sharing_handler.erl

-module(canvas_sharing_handler).
-import(websocket_server, [unicast/2, broadcast/2, sendall/1]).
-compile(export_all).

go() -> websocket_server:start("etsukata.com", 9000, ?MODULE, canvas_sharing_handler, [[],[]]).

canvas_sharing_handler(IDList, PointList) ->
  receive
    {open, ConnectionID} ->
      broadcast("@NC:" ++ ConnectionID, ConnectionID),
      unicast("@ID:" ++ ConnectionID, ConnectionID),
      StrIDList = lists:foldr(fun(X, Xs) -> X ++ "," ++ Xs end, "", IDList),
      Str = case StrIDList of
              []   -> [];
              _Any -> lists:sublist(StrIDList, length(StrIDList) -1)
            end,
      unicast("@PT:" ++ Str, ConnectionID),
      lists:foreach(fun(X) -> unicast(X, ConnectionID) end, lists:reverse(PointList)),
      canvas_sharing_handler([ConnectionID|IDList], PointList);
    {message, Data, ConnectionID} ->
      case lists:member($@, Data) of
        true ->
          case string:substr(Data, 1, 3) of
            "@CU" ->
              broadcast(Data, ConnectionID),
              canvas_sharing_handler(IDList, []);
            _Any ->
              canvas_sharing_handler(IDList, PointList)
          end;
        false ->
          broadcast(Data, ConnectionID),
          canvas_sharing_handler(IDList, [Data|PointList])
      end;
    {closed, ConnectionID} ->
      broadcast("@CL:" ++ ConnectionID, ConnectionID),
      canvas_sharing_handler(lists:delete(ConnectionID,IDList), PointList);
    Any ->
      io:format("Any:~w~n", [Any]),    
      canvas_sharing_handler(IDList, PointList)
  end.
Node.js版のソースコードとほとんど長さは変わっていません。
Node.jsのスピード感のある開発も楽しいです。しかしErlangのメッセージパッシングで考えたほうがほうが単純に物事を捉えることができ、これもまた楽しいのです。僕はNode.jsとErlang、どっちも好きです!

2010/11/11

ErlangでWebSocket Server実装を書きました

こちらで公開しています
https://github.com/Etsukata/erlang_websocket_server
この記事はGithubに公開している情報を日本語で若干加筆して提供いたします。


動機
以前Node.jsのWebSocket Server実装であるnode-websocket-serverを用いてCanvas共有アプリをつくりました。そのとき手軽でスピード感のある開発に快感を覚えたので、ネットワークとの親和性のが非常に高く、今注目を集めているErlangではできないものかと思い、作りました。
Dave Bryson氏による実装であるerlang_websocketを主に参考にさせて頂きました。氏の実装では一対一の相互通信を行うものであったので、それを拡張し、特定のクライアントにデータを送信したり、マルチキャストしたりできるようにしました。
なにより、node-websocket-serverのように手軽にWebSocketを用いたアプリをつくれるようにするのが目的です。

Process Design Pattern
Erlangでシステムを構築するときはどのようなProcess Design Patternを採用するかが鍵になります。当ライブラリでは以下のような構造になっています。



Socket Receiverがクライアントからデータを受け取り、順々に右のプロセスに渡していきます。ReceiverはWebSocket Frameから生のデータを取り出しHandlerに渡します。Handlerはそれを加工しSenderに渡します。SenderはWebSocket Frameをつくり、各クライアントとつながっているSocket Senderに対しユニキャストまたはマルチキャストでデータを配信します。Socket Senderは受け取ったものをクライアントに送信します。
と、いった感じです。
ユーザーはHandlerの振る舞いについてのみ記述すればいいようになっています。

サンプル
エコーサーバーを書く場合は以下で十分です。

-module(echo_handler).
-compile(export_all).
-import(websocket_server, [unicast/2]).
go() ->
   websocket_server:start("localhost", 9000, ?MODULE, default_echo_handler, []).
default_echo_handler() ->
  receive
    {message, Data, ConnectionID} ->
      unicast(Data, ConnectionID),
      default_echo_handler();
    _Any -> default_echo_handler()
  end.

ドキュメント
こちらにあります。
http://etsukata.com/erl/docs/


今後
これからはどのような機能を盛りこんでいくかを決めるために、いくつかこのライブラリを用いたWebSocketアプリをつくっていくつもりです。経験を積んで、何が必要で重要なのか、何が要らない物なのかを見定めたいと思っています。

参考URL
Comet is dead long live websockets
http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html
davebryson / erlang_websocket
https://github.com/davebryson/erlang_websocket
MiCHiLU / erlang_websocket
https://github.com/MiCHiLU/erlang_websocket

2010/11/07

Node.js + Websocket Canvas共有システムが時折ダウンする問題について

2010/10/27にCanvas共有Websocketサーバーを作動させて以来、サーバーがのべ三度にわたりダウンするという問題が発生していました。原因の究明を進めていたところ、一部ダウンする状況の再現及び対処法を突き止めましたのでご報告申し上げます。なお、ダウン中にアクセスされ、Canvas共有を体験なさることが出来なかった読者の方々には深くお詫び申し上げます。これからもダウンの折には早急な原因の解明と対処に努めますので、どうか今後ともよろしくお願いいたします。

サーバーダウン時のエラー出力の内容
node.js:63
    throw e;
    ^
Error: ECONNRESET, Connection reset by peer
    at Stream._readImpl (net:304:14)
    at IOWatcher.callback (net:454:24)
    at node.js:768:9

原因
Node.jsでは発生した例外がイベントループまで到達した場合、デフォルトの動作として、スタックトレースを出力し、終了することになっています。上記の例外が発生した場合、サーバーはダウンします。なお、スタックトレースをご覧いただければわかりますとおり、例外がイベントループ内において発生していますので try/catchで捕まえることはできません。
問題は、どのような状況において上記の例外が発生するか、ということです。
上記の例外は時折にしか発生せず、原因がなにかわからなかったのですが、ようやく突き止めました。Websocketクライアントが正常に接続を終了しない場合に発生していたのです。試しにサーバーへのコネクションを張ったまま、LANケーブルを引っこ抜いてみると、まんまと上記の例外が出ました。おそらくは不安定なネットワーク環境のもとCanvas共有にアクセスし、途中でネットワークが切断された際やブラウザがクラッシュした際等に発生していたのでしょう。

対策
例外発生時の動作をデフォルトのものから変更します。
参照:Event: 'uncaughtException'

ちなみに「Connection reset by peer node.js」で検索したところ、同じ問題で困っていた仲間が大量にいました。


Node.jsで何か作る際には、あらかじめ例外発生時の動作を適切なものに設定なさることをおすすめします。デフォルトだとプロセスは終了してしまいます。
ただ、なんでもprocess.on('uncaughtException')を使って何事もなかったかのようにサーバーを動かし続けることには注意が必要な場合があります。以下を御覧ください。
node.js - Dealing with uncaught exceptions
http://debuggable.com/posts/node-js-dealing-with-uncaught-exceptions:4c933d54-1428-443c-928d-4e1ecbdd56cb

2010/10/27

Node.js + Websocket でCanvas共有

友人のhidekiyさんにNode.jsというこれから流行りそうなおもちゃを紹介してもらったので遊ぼうと思います。
Node.jsはV8 JavaScriptエンジン上でイベント化された入出力を扱うフレームワークです。
Node.jsを用いて簡単な落書き板のようなものをつくりました。Websocketサーバーに接続して、みんなでリアルタイムにCanvasを共有し、書き込むことができます。接続時に、サーバーに落書きデータがある場合はそれをダウンロードしてクライアントのCanvasに書き加えます。
クライアントサイドもサーバーサイドもJavaScriptで書けるって、やっぱり気持ちいいです。

対応ブラウザはSafariとChromeです。
Port:8888 をWebsocketの通信に使用しています。ウイルス対策ソフトのブロッキングやプロキシ環境下においては通信できない可能性がありますのでご注意ください。

ぜひ、落書きしてみてください!
http://etsukata.com/node/cvws.html
↑これです

Sorce codeはサーバーサイド、クライアントサイド共にこちらでご覧いただけます。
http://etsukata.com/node/
サーバーサイド    : cvwsserver.js
クライアントサイド : cvwsclient.js





参考URL:
Node.js
http://nodejs.org/
websocket-server
http://github.com/miksago/node-websocket-server