Sock-09.バイトオーダーとか構造体の話
今回のお題
インターネットの世界では様々な通信機器が存在
→通信相手が自分と同じ環境だとおもうなよ!!!!って話
バイトオーダー
2バイト以上のデータの取り扱いが環境で違う
A君「10000円あげる」 ※short
B君「A君が4135円くれるらしい」
A君「10000円あげる」 ※long(int)
B君「A君が270991360円くれるらしい」
構造体のサイズ
long型の変数 * 1、int型の変数 * 1、short型の変数 * 1、char型の変数*1 ... で構成される構造体のサイズは?
宣言順でかわる…
バイトオーダー
2バイト以上のデータの取り扱い方が環境によって異なる
https://www.coins.tsukuba.ac.jp/~syspro/2010/No6_files/marshaling.html
https://www.coins.tsukuba.ac.jp/~syspro/2010/No6_files/byte-order.png
https://bookstack.yz-learning.com/books/f0935/page/e7b24
陽悦先生に感謝!!
ネットワークバイトオーダー
環境によってバイトオーダーが違っているため、下記のルールが設けられている
ネットワーク上に流す多バイトデータはネットワークバイトオーダーに変換すること
ちなみに、ビッグエンディアン
なので、多バイトデータを送受信する場合は↓となる
送信前:ネットワークバイトオーダーに変換して送信
受信後:各ホストのバイトオーダーに変換して利用
ネットワークバイトオーダーへの変換
hton●()という関数を使うだけ
Host TO Networkの略
●は4バイトならl、2バイトならs...などなど基本データサイズを示すアルファベット
longのl
shortのs
ホストのバイトオーダーへの変換
ntoh●()という関数を使うだけ
Network TO Hostの略
●は4バイトならl、2バイトならs...などなど基本データサイズを示すアルファベット
longのl
shortのs
バイト境界とメモリアラインメント
メモリアラインメント( アライメント )
変数をメモリ上に配置する際に位置調整を行うこと
バイト境界と呼ばれる単位で調整される
バイト境界が4 → アドレスを4の倍数にする
バイト境界が8 → アドレスを8の倍数にする
https://appswingby.com/バイト境界-今更聞けないit用語集/
https://qiita.com/hoboaki/items/46700f03b522193e9747
https://www.ibm.com/docs/ja/zos/2.5.0?topic=issues-data-alignment-problems-when-structures-are-shared
code:sample.cpp
#include <iostream>
using namespace std;
struct HOGE
{
char ch;
short sh; // ここ
long l;
int n;
};
struct FUGA
{
char ch;
long l;
int n;
short sh; // ここ
};
int main(void)
{
cout << sizeof(HOGE) << endl;
cout << sizeof(FUGA) << endl;
return 0;
}
同じメンバ変数だが宣言順によって、余白ができるためサイズが変わる
おまけ
バイト境界を設定することも可能
VC++だと#pragma pack(x)
ただ、処理効率が落ちるのでいやだなーとおもう
要するに今回伝えたいこと!
環境次第でいろいろ変わるから、「通信相手は違うかも」と考えながら作る必要がある!!!
いろいろ違うことを踏まえてアプリケーションプロトコルを考える必要がある
おまけ
recv()・recvfrom()の第4引数flagsをMSG_PEEKに設定すると、受信したデータを受信バッファに残すことができる
構造体の送受信を行う際は、メンバ変数の最初に構造体のサイズを入れる変数を用意
code:sample.cpp
struct HOGE
{
int32_t size; // この構造体のサイズ 32ビット
~以下略~
};
受信時にいったん32ビット( 4バイト )分取得
code:sample.cpp
struct HOGE
{
int32_t size; // この構造体のサイズ 32ビット
~以下略~
};
~省略~
int32_t size; // 送られてくるデータ( 構造体 )のサイズを最初に取得
int ret = recv( sock, (char *)&size, sizeof( size ), MSG_PEEK, ~ ); // recvfrom()でも同様
sizeから送られてきた構造体のサイズがわかるので、
その分のメモリ確保して、データ全体の受信領域を確保
受信しようとしていた構造体のサイズと一致しているかチェック
などしてから、再受信( flagsは0にすること )するってことも可能
code:sample.cpp
struct HOGE
{
int32_t size; // この構造体のサイズ 32ビット
~以下略~
};
~省略~
int32_t size; // 送られてくるデータ( 構造体 )のサイズを最初に取得
int ret = recv( sock, (char *)&size, sizeof( size ), MSG_PEEK, ~ ); // recvfrom()でも同様
~省略~
int ret = recv( sock, 受信したデータの格納領域の先頭アドレス, size, 0, ~ ); // recvfrom()でも同様
#ネットワーク関係
#ネットワークプログラミング