cvl-robot's diary

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

xmlrpc for c and c++(xmlrpc-c)をWindows10, openFrameworks環境で使う

XML-RPCは古いインターフェースですが、Pythonの標準ライブラリでサーバーが簡単に作れるので、C++からPythonを呼び出したい時など、時と場合によっては便利に使えます。以前libxmlrpc++を紹介したことがありますが、今回のはxmlrpc for c and c++(xmlrpc-c)です。違いは、xmlrpc-cは非同期(Asynch≒non-blocking)に対応していること(ただしインターフェースは洗練されていない)です。

CMakeサポート版のフォーク xmlrpc-c

github.com
個人のgraugansさんが作られたもので、5か月ぐらい前が最終更新のタイムスタンプです。
HTTP用の外部ライブラリが必要で、

  • Curl
  • Libwww
  • Wininet

から選んで使います。Curlが推奨されていますが、Windowsでは標準で使えるWininetでも特に問題は感じません。ここでは、Wininetを使うことにします。

CMakeLists.txtを編集

どのライブラリを選択してもfindCurlを必ず呼んでここで引っかかってしまうので、コメントアウトしてしまいます。乱暴なことをしていますので、何があっても責任取れません。自分で判断して使ってください。

#find_package(CURL ${tmp})
#ensc_set_bool(MUST_BUILD_CURL_CLIENT ${CURL_FOUND} "Set if Curl client transport shall be built")

あとは普通にcmakeでconfigureとgenerateしてプロジェクトを作ってください。

build

普通にビルドをすると半分ぐらいビルドできますが、半分ぐらいエラーで落ちます。適当にCMakeLists.txtを適当に編集したためにMUST_BUILD_CURL_CLIENTの定義が抜けてしまっているためです。次のように修正します。
transport_config.h

/* -*- c -*- */
#define MUST_BUILD_WININET_CLIENT	1
#define MUST_BUILD_LIBWWW_CLIENT	0
#define MUST_BUILD_CURL_CLIENT		0 //////

bin, include, libを集める

出力ファイルは何故かあちこちにバラバラに配置されています。

cライブラリは、build/src/ReleaseもしくはDebugに.dllと.libがあります。
c++ライブラリは、build/src/cpp/Release もしくはDebugに.dllと.libファイルがあります。
xmlrpc_util.dllとxmlrpc_util.libは、build/lib/libutil/ReleaseもしくはDebugにあります。

includeファイルは、include/xmlrpc-cにあります。
config.hは、build/include/xmlrpc-cにあります。

自分の都合の良いように、適当なフォルダの中にそれぞれ放り込んでください。

サンプルプログラム

たとえば非同期クライアントを動かしてみます。Curlを使っていませんので、Curl対応の関数を読んでいるところをwininet用関数に置き換えます。
https://sourceforge.net/p/xmlrpc-c/code/HEAD/tree/trunk/examples/cpp/asynch_client.cpp

//xmlrpc_c::clientXmlTransport_curl myTransport;
xmlrpc_c::clientXmlTransport_wininet myTransport;

Resultが構造体だったりArrayだったりするときのデータ受け取り方法

xmlrpc++はとてもスマートに直感的にかけたのですが、xmlrpc-cは残念ながらいまいちです。返り値が構造体の場合は、下記のようにデータを解釈させます。

構造体受信の例

jntという名前のdouble型arrayが入っている構造体の受信例です。

	string const serverUrl("http://192.168.0.11:4321");
	string const methodName("get_joint");

	xmlrpc_c::clientSimple myClient;
	xmlrpc_c::value result;

	myClient.call(serverUrl, methodName, "", &result);

	xmlrpc_c::value_struct s(result.cValue());
	xmlrpc_c::value_array a(s.cvalue()["jnt"]);
	for (int i = 0; i < 6; i++) {
		joint[i] = xmlrpc_c::value_double(a.cvalue()[i]);
	}

構造体送信の例

	xmlrpc_c::clientXmlTransport_wininet myTransport;
	xmlrpc_c::client_xml myClient(&myTransport);

	string const methodName("move_joint");

	xmlrpc_c::carray a;
	for (int i = 0; i < 6; i++) {
		a.push_back(xmlrpc_c::value_double(joint[i]));
	}

	xmlrpc_c::cstruct s;
	s.insert(std::make_pair<std::string, xmlrpc_c::value>("", xmlrpc_c::value_array(a)));

	xmlrpc_c::paramList sampleAddParms1;
	sampleAddParms1.add(xmlrpc_c::value_struct(s));

	xmlrpc_c::rpcPtr rpc1P(methodName, sampleAddParms1);
	string const serverUrl("http://192.168.0.11:4321");

	xmlrpc_c::carriageParm_curl0 myCarriageParm(serverUrl);
	rpc1P->start(&myClient, &myCarriageParm);

		
	myClient.finishAsync(xmlrpc_c::timeout(100));

今日のノートPC

アマゾン専売のMSIの軽量14インチノート。11万円ぐらいでGeForceMX150搭載。自宅用はもうこれで良いね。
[asin:B07D8PJBGS:detail]
[asin:B07FB27SNB:detail]