ここでは、Zenoh-C用環境構築について軽く紹介します。
できれば講習資料としてまとめる予定でしたが、あまり進捗が進んでいなかったので、とりあえずCの使い方のみ先に公開します。
Zenohとは
Zenoh(ゼノー)はzetta scale社が開発しているP2P・クエリ型の通信プロトコルです。
拡張性・速度の速さを謳っており、IoTなど低消費電力デバイスへの搭載・他通信プロトコルとの相互運用性などの点において他プロトコルと比べて優れているそうです。
P2P間のPub/SubからZenohルータを用いたNAT越えを実現することができるので、最近だとROS2のNAT越えに使われたりするそうです。
詳しくは以下の記事で詳しく書かれています。
(公式)
C++のCMakeの書き方(Pub/Sub)
ZenohはベースがRustで書かれており、そこからRust・C/C++・Pythonで叩けるAPIを提供しています。(C/C++ APIについてはビルド元が同じでヘッダーが異なる感じ)
PythonとRustであれば環境構築はわかりやすいのですが、CMakeListsを書く必要があるので結構面倒&時間がかかるのでメモを残します。(ついでに冗長な部分を省いたサンプルも残しておきます)
Zenohを採用するついでにRustに移行すれば全く問題ない話ではあるのですが。
環境構築
Ubuntu22.04を使用しました。
同じディレクトリ内にpub.c・sub.c・CMakeLists.txtを作成し、buildディレクトリ内でビルドをする想定です。
| |-- pub.c |-- sub.c |-- CMakeLists.txt |-- build | |- (ビルド時に生成されるであろうファイル)
zenoh-cの自体ビルドは次のとおり。
libzenoh-cにはヘッダー情報しかなかったようでビルドがうまく行かなかったので、直ビルドが必要です。
※ライブラリのビルドのためにRustのビルド環境が必要です:Install Rust - Rust Programming Language
git clone https://github.com/eclipse-zenoh/zenoh-c.git cd zenoh-c/ mkdir build cd build/ cmake .. cmake --build . --config Release sudo cmake --build . --target install
空ファイル作成
コピペしやすいように空ファイルを作成しておきます。
VSCodeなら開いたファイルウィンドウにコードを貼り付けるだけでOKです。
mkdir -p zenohc_example/build touch zenohc_example/pub.c && touch zenohc_example/sub.c && touch z_example/CMakeLists.txt ## VSCodeがインストールされている場合 # code zenohc_example/pub.c zenohc_example/sub.c zenohc_example/CMakeLists.txt
pub側
単純にカウントアップしていくプログラムです。
#include <stdio.h> #include <string.h> #include <unistd.h> #include "zenoh.h" int main(int argc, char **argv) { char *keyexpr = "namespace_a/topic_a_1"; char *value = "Pub from C!"; char buf[256]; int i = 0; z_owned_config_t config = z_config_default(); printf("Opening session...\n"); z_owned_session_t s = z_open(z_move(config)); printf("Declaring Publisher on '%s'...\n", keyexpr); z_owned_publisher_t pub = z_declare_publisher(z_loan(s), z_keyexpr(keyexpr), NULL); while (i < 100) { sprintf(buf, "[%4d] %s", i, value); printf("Putting Data ('%s': '%s')...\n", keyexpr, buf); z_publisher_put_options_t options = z_publisher_put_options_default(); options.encoding = z_encoding(Z_ENCODING_PREFIX_TEXT_PLAIN, NULL); z_publisher_put(z_loan(pub), (const uint8_t *)buf, strlen(buf), &options); sleep(1); i++; }; z_undeclare_publisher(z_move(pub)); z_close(z_move(s)); return 0; }
sub側
受信したものをそのまま出力しています。
#include <stdio.h> #include <string.h> #include <unistd.h> #include "zenoh.h" void data_handler(const z_sample_t *sample, void *arg) { z_owned_str_t keystr = z_keyexpr_to_string(sample->keyexpr); char recieved_type[10]; switch (sample->kind) { case Z_SAMPLE_KIND_PUT: strcpy(recieved_type, "PUT"); break; case Z_SAMPLE_KIND_DELETE: strcpy(recieved_type, "DELETE"); break; } printf(">> Received %s ('%s': '%.*s')\n", recieved_type, z_loan(keystr), (int)sample->payload.len, sample->payload.start); z_drop(z_move(keystr)); } int main(int argc, char **argv) { char c = 0; char *expr = "namespace_a/topic_a_1"; z_owned_config_t config = z_config_default(); // Open a session z_owned_session_t s = z_open(z_move(config)); z_owned_closure_sample_t callback = z_closure(data_handler); printf("Declaring Subscriber on '%s'...\n", expr); z_owned_subscriber_t sub = z_declare_subscriber(z_loan(s), z_keyexpr(expr), z_move(callback), NULL); printf("Enter 'q' to quit...\n"); while (c != 'q') { c = getchar(); if (c == -1) { sleep(1); } } z_undeclare_subscriber(z_move(sub)); z_close(z_move(s)); return 0; }
CMakeLists.txt
ターゲット直指定でビルドする場合の最小構成
find_package(zenohc REQUIRED) add_executable(pub pub.c) target_link_libraries(pub zenohc::lib) add_executable(sub sub.c) target_link_libraries(sub zenohc::lib)
ファイルをGLOBでまとめて取得する場合
(ついでにcmake_minimum_requiredとprojectを追加し CMake Warning
を除く)
cmake_minimum_required(VERSION 3.20) project(zenohc_examples LANGUAGES C) find_package(zenohc REQUIRED) # get all build target file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.c") foreach(file ${files}) get_filename_component(target ${file} NAME_WE) add_executable(${target} ${file}) target_link_libraries(${target} PRIVATE zenohc::lib) endforeach()
実行
1つめのターミナル
./pub
2つめのターミナル
./sub
参考資料(GitHub)
他にもいろいろなオプションがあり、データ型をカスタマイズすることや通信方式を調整することもできるそうです。