cvl-robot's diary

研究ノート メモメモ https://github.com/dotchang/

ofxZmqをopenFrameworks0.9.0RCとVisualStudio2015で動かしてみる

ofxZmqは、satoruhigaさんの作られたopenFrameworks addonで、メッセージ通信ミドルウェアZeroMQ(0MQ)のラッパーです。
比較的最近のものまでメンテナンスされていますので問題なく動くと思うのですが、オリジナルはMacで開発されているようなのでWindowsで動かすことから始めます。
github.com
Distributed Messaging - zeromq

1.ダウンロードとインストール

いつものように、download zipボタンを押して持ってきて、解凍して、名前の-masterを削って、openFrameworks0.9RCのaddonフォルダの中にコピーします。
openFrameworksのprojectGeneratorを使って、example用の空のプロジェクトを作ります。その際に、addonsにofxZmqのチェックを入れます。
addonフォルダの中のexample/srcを、新しく作った空のプロジェクトに上書きコピーします。

2.プロジェクトのビルド

若干古いバージョンに対応して作られているため命名ルールが今のものと違くて、ofApp.cpp, ofApp.hにあたるファイル名がtestApp.cpp、testApp.hになっています。
プロジェクトに読み込むファイルを、ソリューションエクスプローラからtestAppのものに変更してください。

最新版のzmqソースコードに置き換え

Get The Software - zeromq
このページで配布されているWindows版の最新のソースコードを持ってきて解凍します。

このソースとaddonプロジェクトの中のlibsフォルダのソースを差し替えます。
プロジェクトのlibs\zmp\の下のincludeとsrcを一度解放してしまい、再度新しいフィルターを追加してincludeとsrcを作ってから、全ソースファイルを読み込むと混乱が無くて済みます。

\zeromq-4.1.3\builds\msvc\platform.hppをコピーして、srcフォルダの中に入れます。その際ついでに、#define ZMQ_HAVE_WINDOWSの下に#define ZMQ_USE_SELECTを追加します。

#ifndef __ZMQ_PLATFORM_HPP_INCLUDED__
#define __ZMQ_PLATFORM_HPP_INCLUDED__

//  This is the platform definition for the MSVC platform.
//  As a first step of the build process it is copied to
//  zmq directory to take place of platform.hpp generated from
//  platform.hpp.in on platforms supported by GNU autotools.
//  Place any MSVC-specific definitions here.

#define ZMQ_HAVE_WINDOWS
#define ZMQ_USE_SELECT    /////add

#endif

つぎに、zmqのcppバインディング用のzmq.hppを次のgithubのリンク先から持ってきて、includeフォルダの中に入れます。
C++ Binding - zeromq

ライブラリの方のファイルも一か所修正しておきます。if_nametoindex関数を使えるようにするためのものです。
tcp_address.cpp

...
#ifdef ZMQ_HAVE_WINDOWS
#include "windows.hpp"
#include <netioapi.h> // added
#else
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#endif
...

それから、プロジェクトをビルドすると一応通るはずです。しかし、Debugモードで実行するとzmq.hppの385行目でアサーションエラーとか言って怒られます。
ちょっと原因がよくわからないのですが、ここを一時的にコメントアウトしてしまいます。(後々問題が起こる可能性、大ですので注意。)

        inline explicit context_t (int io_threads_, int max_sockets_ = ZMQ_MAX_SOCKETS_DFLT)
        {
            ptr = zmq_ctx_new ();
            if (ptr == NULL)
                throw error_t ();

            int rc = zmq_ctx_set (ptr, ZMQ_IO_THREADS, io_threads_);
            ZMQ_ASSERT (rc == 0);

            rc = zmq_ctx_set (ptr, ZMQ_MAX_SOCKETS, max_sockets_);
           // ZMQ_ASSERT (rc == 0); // for debug
        }

3.実行

実行してみると、何かのキーを押すたびに、ローカルでメッセージのやり取りをして次のようなメッセージが出ます。
f:id:cvl-robot:20150826150333p:plain
一応、動いているみたいですね。

ほかのライブラリをリンクして動かそうとすると、起動すらせずに落ちてしまうことがあるようです。
これはおそらく、MSVC2015になってメモリ管理が厳格になってしまったためで、グローバルに大きなメモリ領域を確保しようとすると動かないことが増えました。
なので、仕方なくアクティブにメモリを取るように書き換えます。

#include "testApp.h"

#include "ofxZmq.h"

ofxZmqSubscriber* subscriber;
ofxZmqPublisher* publisher;

//--------------------------------------------------------------
void testApp::setup()
{
	subscriber = new ofxZmqSubscriber();
	publisher = new ofxZmqPublisher();

	// start server
	publisher->bind("tcp://*:9999");

	// start client
	subscriber->connect("tcp://localhost:9999");
}

//--------------------------------------------------------------
void testApp::update()
{
	while (subscriber->hasWaitingMessage())
	{
		ofBuffer data;
		subscriber->getNextMessage(data);

		cout << "received data: " << data << endl;
	}
}

//--------------------------------------------------------------
void testApp::draw()
{
}

//--------------------------------------------------------------
void testApp::keyPressed(int key)
{
	if (!publisher->send("this is a test"))
	{
		cout << "send failed" << endl;
	}
}

//--------------------------------------------------------------
void testApp::keyReleased(int key)
{

}

//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y)
{

}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button)
{

}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button)
{

}

//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button)
{

}

//--------------------------------------------------------------
void testApp::windowResized(int w, int h)
{

}

//--------------------------------------------------------------
void testApp::gotMessage(ofMessage msg)
{

}

//--------------------------------------------------------------
void testApp::dragEvent(ofDragInfo dragInfo)
{

}

OscReceivedElements.hに次を足しておくと便利。

ReceivedMessage(const char* data, size_t size) : addressPattern_(data) { Init(data, size); }

[1] ofxZmq https://github.com/satoruhiga/ofxZmq
[2] zeromq http://zeromq.org/
[3] ZMQマニュアル日本語訳http://www.cuspy.org/diary/2015-05-07-zmq/zguide-ja.pdf
[4] 分散型メッセージングミドルウェアの詳細比較 | インフラ・ミドルウェア | POSTD

ZeroMQ: Messaging for Many Applications

ZeroMQ: Messaging for Many Applications