Node.jsでブラウザを使わないWebSocketクライアント

Node.jsを使い始めたのは、WebSocketを使ってごにょごにょしたいからだった。通常と少し違うのは、WebSocketのクライアント側がブラウザでは無いこと。それを実現するにはどうしたら良いか調べた。

Node.jsでWebSocketを使うには

Node.jsでWebSocketを使う場合、Socket.IOというモジュールを使うのが一般的らしい。厳密にいうと、Socket.IOはクライアントのブラウザがWebSocketをサポートしていない場合、自動で他の手段で代替してくれるとのこと。

 

本家

Socket.IO: the cross-browser WebSocket for realtime apps.

日本語版ページ

Socket.IO: the cross-browser WebSocket for realtime apps.

 

Node.jsのモジュールは、npmコマンドでインストールできる。Socket.IOのモジュールをインストールするには、下記のコマンドになる。

$ npm install socket.io 

これだけで、特に引っかかることなく、Soket.IOのサンプルコードを動かすことができた。

http://socket.io/#how-to-use

 

なんか、ものすごく簡単ですね。この使いやすさが広く使われている理由のひとつなのかな。 

ただし、これらのサンプルは、全てクライアントがブラウザであることを想定したものばかり。自分としては、クライアント側もNode.jsオンリーで書きたい。どうすれば良いか?

ブラウザを使わないSocket.IOのクライアント

世の中には、大体同じようなことを考えている人がいるもので、「node socket.io client no browser」というキーワードでググッたらすぐに答えが出てきた。

 

Added preliminary support for socket.io-client to work from node.js by josephg · Pull Request #240 · LearnBoost/socket.io-client · GitHub

socket.io-clientというものを使えば良いらしい。

 

早速、モジュールをインストールしてみる。

$ npm install  socket.io-client

 

で、↑のリンクにあったサンプルコードを動かしてみる。

 

まず、サーバー側(socket_server.js)

 var io = require('socket.io').listen(8080);

 

io.sockets.on('connection', function (socket) {

    socket.emit('news', {hello: 'world'});

    socket.on('my other evenr', function (data) {

        console.log(data);

    });

});

 

クライアント側(socket_client.js)

 var io = require('socket.io-client');

var socket = io.connect('http://localhost:8080');

 

socket.on('news', function (data) {

    console.log(data);

    socket.emit('my other evenr', {my: 'data'});

});

実行結果

$ node socket_server.js

   info  - socket.io started

   debug - client authorized

   info  - handshake authorized pl-ax4lmk3PJB8ai5fQd

   debug - setting request GET /socket.io/1/websocket/pl-ax4lmk3PJB8ai5fQd

   debug - set heartbeat interval for client pl-ax4lmk3PJB8ai5fQd

   debug - client authorized for

   debug - websocket writing 1::

   debug - websocket writing 5:::{"name":"news","args":[{"hello":"world"}]}

{ my: 'data' }

$ node socket_client.js

{ hello: 'world' }

 

これまた、簡単にできた。

 

次は、クライアントAとクライアントBの間で、WebSocketサーバー経由でデータのやり取りをしたい。これは、Socket.IOの名前空間を使えば、実現できそうな気がする。

はじめての Node.js

ちょっと作ってみたいものが出来たので、Node.jsの使い方を勉強中。

(本当はWebSocketを使ってごにょごにょしたい)

 

使用した環境

Debian GNU/Linux 7.1 (Wheezy)

 

インストール

Debian公式のdebパッケージは基本的にバージョンアップされないので、Node.jsのように更新速度が速いものは、別の手法で管理したほうが良い。(そもそも、nodejsパッケージはsidにしかない。。)

 

Node.jsの管理ツールとしてはいくつかあるようだけれど、検索して色々情報が出てきたnvm(Node Version Manager)というものを使ってインストール。他には、naveとかnodebrewとか色々あるみたい。

$ curl https://raw.github.com/creationix/nvm/master/install.sh | sh 

 

環境変数PATHの設定もしてくれたらしいので、ターミナルを再起動

 

とりあえず、現在の安定版の最新をインストール

$ nvm install v0.10.16 

hello world

Node界隈ではhello worldとしてHelloを返すHTTPサーバーを実装するものらしいので、動かしてみる。

 

hello.jsという名前で、下記コードを記述。

var http = require('http');

 

var server = http.createServer();

 

server.on('request', function(request, response) {

    console.log(request.url);

    response.writeHead(200, {'Content-Type': 'text/plain'});

    response.end('hello ' + request.url);

});

 

server.listen(8080, 'localhost');

 nodeコマンドで実行。

$ node hello.js

別の端末から

$ curl http://localhost:8080

hello /

はOK。

 

じゃあ、IP直打ちでもいけるかなーと思ったけど、下記はダメ。

$ curl http://(サーバーのIPアドレス):8080

curl: (7) couldn't connect to host 

iptablesでブロックしているわけでもなし。。*1

$ sudo iptables -L

Chain INPUT (policy ACCEPT)

target     prot opt source               destination

 

Chain FORWARD (policy ACCEPT)

target     prot opt source               destination

 

Chain OUTPUT (policy ACCEPT)

target     prot opt source               destination

 

そもそも、127.0.0.1(localhost)でしかlistenしてないぞ。。

$ netstat -ant | grep 8080

tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN

あれこれ悩んだ結果、hello.jsの最後の一行を下記に書き換えることで、意図した通りに動いた。

- server.listen(8080, 'localhost');

+ server.listen(8080, 'IPアドレス');

もしくは、ホスト名を指定しなければ、localhostでも、IPアドレス直打ちでも動作する。

- server.listen(8080, 'localhost');

+ server.listen(8080);

第三引数 hostname はオプションなので、必ずしも指定する必要は無かった。

ちゃんとリファレンスを読みましょう。というオチ。

http://nodejs.org/api/http.html#http_server_listen_port_hostname_backlog_callback

 

参考文献

松島浩道「はじめての Node.js -サーバーサイドJavaScriptでWebアプリを開発する-」ソフトバンククリエイティブ

 

*1:この設定はWheezyのデフォルトまんまで、全てのアクセスを受け入れているので、よろしくない。

OpenCV 2.2をARM用にクロスビルドしたらハマった件

OpenCVをARM用にクロスコンパイルしたところ、色々ハマったのでメモ。

環境

手順

基本は、以下のページを参考に。
OpenCV Installation Guide on Debian and Ubuntu

OpenCVはビルドシステムにCMakeを使っているので、以下のページを見ながらtoolchain fileというのを作る。
CMake Cross Compiling

最終的に、手順は以下のようになった。

  1. 必要なクロスライブラリをひたすらインストール*2
  2. tar xjvf OpenCV-2.2.0.tar.bz2
  3. cd OpenCV-2.2.0
  4. mkdir armel
  5. cd armel
  6. vi armel.cmake
  7. cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_TOOLCHAIN_FILE:PATH=./armel.cmake ..
  8. make
  9. make install

armel.cmakeの中身は以下*3

set(CROSS_PREFIX arm-linux-gnueabi-)
set(CROSS_TOOLCHAIN_PATH /usr/arm-linux-gnueabi)

# specify the cross-toolchain (compiler, header and library directories)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR armel)
set(CMAKE_C_COMPILER ${CROSS_PREFIX}gcc)
set(CMAKE_CXX_COMPILER ${CROSS_PREFIX}g++)
set(CMAKE_INCLUDE_PATH ${CROSS_TOOLCHAIN_PATH}/include)
set(CMAKE_LIBRARY_PATH ${CROSS_TOOLCHAIN_PATH}/lib)
set(CMAKE_INSTALL_PREFIX ${CROSS_TOOLCHAIN_PATH}/)

#set(CMAKE_FIND_ROOT_PATH ${ARMADEUS_ROOT_CTC} ${CMAKE_INCLUDE_PATH})

# search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH ${CROSS_TOOLCHAIN_PATH})

# for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

ハマりポイント

普通にビルドするとビルドエラーが出るので、いくつか修正します。

expl が定義されていない

エラーメッセージ

/root/OpenCV-2.2.0/modules/ml/src/gbt.cpp:474: error: 'expl' was not declared in this scope

以下の修正を適用。

fixed GBTrees build on NetBSD & Android; fixed GPU brute force matcher test build on MacOSX

SIFTが未定義*4

エラーメッセージ

../../lib/libopencv_features2d.so.2.2.0: undefined reference to `cv::SIFT::SIFT(double, bool, bool, int, int, int, int)'
../../lib/libopencv_features2d.so.2.2.0: undefined reference to `cv::SIFT::CommonParams::CommonParams()'
../../lib/libopencv_features2d.so.2.2.0: undefined reference to `cv::SIFT::DescriptorParams::DescriptorParams()'
../../lib/libopencv_features2d.so.2.2.0: undefined reference to `cv::SIFT::DetectorParams::DetectorParams()'
../../lib/libopencv_features2d.so.2.2.0: undefined reference to `cv::SIFT::operator()(cv::Mat const&, cv::Mat const&, std::vector >&, cv::Mat&, bool) const'
../../lib/libopencv_features2d.so.2.2.0: undefined reference to `cv::SIFT::operator()(cv::Mat const&, cv::Mat const&, std::vector >&) const'
../../lib/libopencv_features2d.so.2.2.0: undefined reference to `cv::SIFT::SIFT(double, double, int, int, int, int)'

以下の修正を適用。

added empty implementation of SIFT class methods throwing exception if ARM


さすが、元々Intelのプロジェクトだっただけあって、Intel以外のプラットフォームではあまりテストされてないっぽいですね。

*1:Squeeze使えよというツッコミは無しの方向でお願いします。

*2:[http://armadillo.atmark-techno.com/howto/install-cross-libraries:title=クロス開発用ライブラリをインストールする方法]とか参照。

*3:どうも、ライブラリがインストールされているかどうかの判断を、ビルドPCのライブラリを見て判断してるっぽいので、何か間違ってるはず。

*4:[http://d.hatena.ne.jp/kokekome/20110204/1296821782:title=OpenCV 2.2 - kokekomeのハードウェアな日記?]がきっかけで、この問題に気づきました。ありがとうございます。

Git の便利コマンド色々 〜ソースコードリーディング編〜

分散型のバージョン管理システムとして利用者も増えてきた(ような気がする) Git ですが、単なるバージョン管理システムとしての機能以外にも色々と便利な機能があったりします。

今回は、ソースコードリーディングに使える Git の便利なコマンドをご紹介します。

git grep

Git で管理されているファイルを grep します。find + grep よりも高速に grep してくれます。

じっくりとソースコードを読み込むのであればタグ管理システムを使いたくなりますが、さっと確認したいというときや、タグで管理できないエラーメッセージを手がかりにソースコードを読むときなどに重宝します。

git grep -e <pattern>

として、検索パターンを指定します。パターンには正規表現をつかうことができます。-e は省略可能です。

パターンは複数指定することもできます。--and/--or/--not でパターンをどのように組み合わせるか指定できます。デフォルトでは、or で結合されます。

git grep -e <pattern> -- <path>

指定したパスのみを検索対象とします。

git log

git log は、リポジトリのコミットログを表示するコマンドです。

git log は豊富なオプションを指定できます。オプションを駆使することで、ソースコードを時系列で追うことが可能になります。

diff (差分) を表示する
git log -p
git log --stat

-p オプションをつけると、各コミットでの diff も表示してくれるので、より詳細に変更点を確認することができます。

変更されたファイルの概要だけ知りたいときは、diffstat を表示してくれる --stat オプションが便利です。

区間を指定する
git log <since>..<until>

とすると、since コミットから until コミットまでのコミットログを表示してくれます。

パスを指定する
git log <path>
git log <since>..<until> -- <path>
git log -p --full-diff <path>

path を指定すると、path で指定したディレクトリまたはファイルに関する変更を含んだコミットログのみを表示してくれます。区間指定と合わせて使用する場合は、 間に -- を入れます。また、git log -p とすると、指定したパスに関する diff のみ含んだコミットログになりますが、--full-diff をつけると、指定したパス以外も含んだ全ての diff を表示してくれます。

git describe

指定したコミットを近いタグを含んだ表現で表してくれます。

git describe --contains

とすると、そのコミットを含む(そのコミットよりも後につけられた)タグで表現してくれます。Linux カーネルなどバージョンごとにタグを打っているリポジトリでは、指定したコミットがどのバージョンに含まれているのか知ることができます。

git blame

ソースコードの各行が、どのコミットで変更されたものか表示してくれます。

-L オプションで、どの行を対象とするか指定することができます。

まとめ

Git の豊富なコマンドの中から、ソースコードリーディングに使えそうなコマンドをご紹介しました。

それぞれのコマンドには、他にも豊富なオプションがあります。man ページ等で確認してみてください。

Git は使い込めば使い込むほど便利になっていくツールという感じがしています。他にも便利なコマンドがあれば、是非教えて下さい。

Androidカーネルの差分をもう少し華麗にゲットするTips

Android Zaurusの日記 「Androidカーネルの差分を華麗にゲットするTips」が素敵だったので、自分ならこうやるかなあ、という方法をご紹介。


引用元では .git ディレクトリの中を直接覗いていますが、ここでは git コマンドを使ってやってみます。最終的にやってることは同じです。


まず、リポジトリを clone します。

$ git clone git://android.git.kernel.org/kernel/common.git
$ cd common


clone してきた branch を確認します。

$ git branch
* android-2.6.27

android-2.6.27 という branch しかローカルにはありません。


リモートの branch は、git remote show コマンドで確認できます。

$ git remote show origin
* remote origin
  URL: git://android.git.kernel.org/kernel/common.git
  Remote branch merged with 'git pull' while on branch android-2.6.27
    android-2.6.27
  Tracked remote branches
    android-2.6.25
    android-2.6.27
    android-2.6.29
    android-2.6.32
    android-goldfish-2.6.27
    android-goldfish-2.6.29

android-2.6.32 などの branch があることが分かります。


次に、タグを確認します。タグの確認は、git tag コマンドです。

$ git tag
v2.6.11
v2.6.11-tree
v2.6.12
v2.6.12-rc2
v2.6.12-rc3
(略)
v2.6.31-rc9
v2.6.32
v2.6.32-rc1
v2.6.32-rc2
v2.6.32-rc3
v2.6.32-rc4
v2.6.32-rc5
v2.6.32-rc6
v2.6.32-rc7
v2.6.32-rc8


ローカルとリモートのブランチで diff を取ります。tags/v2.6.32 という指定は v2.6.32 に省略できます。
とりあえず、全体的にどのような変更が入ったのかを確認したいので、--stat オプションで diffstat を表示してみます。

$ git diff --stat v2.6.32..origin/android-2.6.32
 Documentation/android.txt                     |  121 +
 arch/arm/boot/compressed/head.S               |    5 +-
 arch/arm/boot/compressed/misc.c               |    2 +-
 arch/arm/configs/msm_defconfig                |    2 +
 arch/arm/kernel/debug.S                       |    2 +-
 arch/arm/kernel/entry-armv.S                  |    5 +-
 arch/arm/kernel/process.c                     |   73 +
 arch/arm/kernel/signal.c                      |    9 +
 arch/arm/kernel/traps.c                       |    5 +-
 arch/arm/mm/cache-v6.S                        |   17 +
 block/blk-core.c                              |    5 +-
 block/genhd.c                                 |   17 +
 drivers/Kconfig                               |    2 +
(略)


個人的には、リモートの branch をローカルに持ってくるやり方の方が好きです。リモートに変更が入ったとき、pull すれば追随できるので。
リモートの branch をローカルにもってくるには、 fetch コマンドを使います。

$ git fetch origin android-2.6.32:android-2.6.32
From git://android.git.kernel.org/kernel/common
 * [new branch]      android-2.6.32 -> android-2.6.32
$ git branch
* android-2.6.27
  android-2.6.32


タグとローカルの branch で diff を取ります。

$ git diff --stat v2.6.32..android-2.6.32
 Documentation/android.txt                     |  121 +
 arch/arm/boot/compressed/head.S               |    5 +-
 arch/arm/boot/compressed/misc.c               |    2 +-
 arch/arm/configs/msm_defconfig                |    2 +
 arch/arm/kernel/debug.S                       |    2 +-
 arch/arm/kernel/entry-armv.S                  |    5 +-
 arch/arm/kernel/process.c                     |   73 +
 arch/arm/kernel/signal.c                      |    9 +
 arch/arm/kernel/traps.c                       |    5 +-
 arch/arm/mm/cache-v6.S                        |   17 +
 block/blk-core.c                              |    5 +-
 block/genhd.c                                 |   17 +
 drivers/Kconfig                               |    2 +
 drivers/Makefile                              |    1 +
 drivers/base/power/main.c                     |   45 +
 drivers/char/Kconfig                          |   17 +
(略)


引用元の blog とほとんど変わんないですね。。.git ディレクトリの中を覗かずに、git コマンドでできるよということが書きたかったのです。


2年ぶりに blog を書きました。これからぼちぼち更新再開できるといいな。