シリアライズライブラリ
ソケット通信でデータを送受信するとき、ネットワークバイトオーダや構造体のパディングなどを考慮して、通信用バイト列に変換する必要がある。
自分でゴリゴリ作るより、便利そうなライブラリを探し、使うことにする。
- Google Protocol Buffers
- MessagePack
- Cereal
Google Protocol Buffers
MessagePack
MessagePack: It's like JSON. but fast and small.
Cereal
【ソケット通信】ネットワークバイトオーダと recv の戻り値
C言語のソケット通信プログラムの続き。固定長文字列の送受信まで昨日成功していたので、shot int(16bit) や int(32bit) ,long(64bit) など、ネットワークバイトオーダが問題となるデータを送受信するサンプルを今日動かした。
が。簡単だと思ってやってみると、嵌った。原因は2つ。
特定の値(例えば-1111)がくるまで送受信を続ける、という仕様で作っていた。
が。特定の値を受け取るまで、受信データを表示せず、特定の値を受け取ると、ループを抜けるはずが無限に特定の値を表示し続ける、という不具合になった。
ループの終了条件を受信データの値で行っていた。
if( dataEnd == buf ) break;
この時、バッファの値はネットワークバイトオーダ(ビックエンディアン)なので、元データにするんは
int16_t data = ntohs(buf);
と変換してから、dataEnd と比較する。
しかし。これでは不十分らしい。ループを抜けなかった。
recv() の戻り値をチェックしたところ、無事にループを抜けた。
int16_t なデータを送受信したので、受信データのサイズは 2が正解。
たまたま終了データとして選んだ -1111を受信すると、データサイズが0になるようだった。
なぜそうなるのかは不明。なので、
int rcv_len = recv( sd, &buf, sizeof(int16_t), 0);
if( rcv_len != 2) break;
とすると、無限ループを抜けることができた。
【ソケット通信】CとC++ サンプルコードの修正
動いたサンプルをベースに、言語をまたいでクライアント/サーバのソケット通信をするため、通信仕様を揃えるべく、修正。
昨日、C言語の修正がうまく行かなかったのは、送受信のときにデータ長を固定で送受信しなかったこと。可変長でテストしてしまった。
その点を修正したら問題なく通信できた。
その後、C++のサンプルを修正。クライアントから終了文字列を送るまで、繰り返し文字列を送った。
で。改めて思った。実用化するには送受信のデータ構造を明確にしないと、ちゃんと通信できない。想定する送受信データ。
- 測定日時
- センサ種類
- センサの測定値
- 測定地点ID
これらを構造体で定義して、クライアント/サーバで共有する必要がある。
さらに、真面目にやるとネットワークバイトオーダを考慮して、送受信する必要がある。
C言語でソケット通信
漸くC言語でクライアント・サーバなソケット通信プログラムのサンプルが動いた。
ネット上のサンプルと、微妙にヘッダファイルの名前やパスが違っていて手こずった。
これで、C/C++/python の3言語で、それぞれクライアントとサーバのサンプルが動いたことになる。
あ、そういえばあと nc(netcat)によるクライアント・サーバもあった(^^)
本番は、サーバ側はC++または python, クライアント側は C言語になる予定。その理由は、サーバ側は
を想定している。
クライアント側は IoT なデバイスとして
- ESP32
- ESP8266(WROOM-02)
- RasPi Zero W
- mbed(Nucreo) + ESP8266
といったものを想定している。なので、クライアント側はほぼC言語、サーバ側はなんでもありだ。
本来は、送受信するデータ構造の設計が必要。ネットワークバイトオーダや、構造体のパディングなどを考慮して、送信データにするための変換処理が必要。
- 固定長文字列
- 構造体
- ヘッダ(データサイズ)
- データの欠損/破壊等の検出用フラグ
など、真面目に考えると大変。可変長に対応するとか、ヘッダの構造が複雑になる。
nc(netcat) on ubuntu
サーバ・クライアント間のソケット通信サンプルプログラムの動作確認などに便利なコマンドを発見。
とゆーか、以前見かけたことがあるので再発見である。かなり便利そうなので、使いながら覚えていきたい。