システムプログラム(第6回): marshaling/unmarshaling
筑波大学 システム情報系 情報工学域
新城 靖
<yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
https://www.coins.tsukuba.ac.jp/~syspro/2024/2024-07-03/marshaling.html
あるいは、次のページから手繰っていくこともできます。
https://www.coins.tsukuba.ac.jp/~syspro/2024/
http://www.coins.tsukuba.ac.jp/~yas/
marshaling/unmarshaling
プログラム中のデータ項目とネットワーク上を流れるメッセージに対応づける。
- marshaling (整列化)
- メモリ中からデータ項目を集めて、ネットワークでメッセージとして
転送するのに適した形式にまとめる。
- unmarshaling (非整列化)
- 逆。
英語の綴りは、l が1つのものと2つのもの(イギリス綴り)がある。教科書によって違う。
図? marshalingとunmarshaling
4個の要素からなる構造体を整列化して送信している。
- 整数
- 文字列
- ビットマップデータ(可変長)のバイト数
- ビットマップデータ(可変長)の本体
整列化する基本的な方法
- 構造体や配列の要素を先頭から順にバッファに追加する。
- 可変長のデータの場合、まず、要素数を追加し、それに続いて本体を追加する。
ネットワークからデータを受け取ると、先頭から解釈して元のデータを再現す
る。
ネットワーク上を流れている時には、整列化された
データの先頭にはネットワークのヘッダが付加されている。
整数のmarshaling
分散プログラムでは、メッセージを送信するプロセスと受信するプロセスが異
なる CPU で実行されることがある。整数をmarshalingする時には、次のような
点を考慮する必要がある。
- ワード(基本的な整数データ)が 8bit/16bit/32bit/64bit と違うことがある。
C 言語の int 型のビット数が違う。
- 1バイトのビット数は、現在は、8ビットのものが主流。
(1バイトが9ビットのものもあった。)
- メモリには、バイト単位で番地が付けられているものが主流。
(ビット単位、ワード単位で番地を付ける方法も考えられる。)
- バイト・オーダが違うことがある。
バイト・オーダ
整数を送るだけでも、バイトオーダに気をつける必要がある。
C言語で扱える整数
- 1 バイト(char)
- 2バイト(short)
- 4バイト(long)
C言語で扱える整数の例(コンパイラによって異なる)。
- LP32
- 1バイト: char
- 2バイト: short
- 4バイト: int, long, ポインタ
- 8バイト: long long
- LP64
- 1バイト: char
- 2バイト: short
- 4バイト: int
- 8バイト: long, ポインタ, long long
- その他
(現在のコンピュータのほとんどは、バイト単位でアドレスを付けているので、
1バイトの整数については、バイトオーダの問題はない。)
2バイト、または、4バイトの整数をメモリに保存する方法
: メモリの下位番地に上位バイトを置くか下位バイトを置くか
- リトルエンディアン
- 下位番地に下位バイトを置く。x86 (Intel, AMD), ARM。
- ビッグエンディアン。
- 下位番地に上位バイトを置く。PowerPC, SPARC, m68k
PowerPC は、両方切り替え可能だが、ビッグエンディアンで使うことが多い。
ARM-32 ビットは、 両方切り替え可能だが、リトルエンディアンで使うことが多い。
ARM-64 ビットは、命令は必ずリトルエンディアンで、データも普通リトルエンディアンだが、
ビッグエンディアンが扱える実装もある。
◆0x2000番地に0x12345678を保存/saving 0x12345678 to the address 0x2000
main()
{
int *p;
p = (int *)0x2000;
*p = 0x12345678;
}
.globl _main
.align 4, 0x90
_main:
pushq %rbp
movq %rsp, %rbp
movl $305419896, 8192
popq %rbp
ret
図? バイト・オーダ(byte order)
バイト・オーダが異なることも考慮した整数の送受信
- 送信側、または、受信側で相手に合わせて変換する。バイトオーダが同
じ場合は何もしない。
- 標準的なバイトオーダ(ネットワーク・バイト・オーダ) を定める。送
信側では、ネットワークにデータを流す時には、常に自分自身のバイト・オー
ダ(ホスト・バイト・オーダ)をネットワーク・バイト・オーダに変換する。
受信側では、ネットワーク・バイト・オーダから自分のホスト・バイト・オー
ダに変換する。
現在、ネットワーク・バイト・オーダとしては、ビッグエンディアンが広く
使われている。
- TCP/IP の IP アドレスやポート番号
- XDR
バイトオーダを変換するライブラリ関数
名前 | 方向 | ビット数 |
uint32_t htonl(uint32_t hostlong) | ホストからネットワークへ変換 | 32ビット |
uint16_t htons(uint16_t hostshort) | ホストからネットワークへ変換 | 16ビット |
uint32_t ntohl(uint32_t netlong) | ネットワークからホストへ変換 | 32ビット |
uint16_t ntohs(uint16_t netshort) | ネットワークからホストへ変換 | 16ビット |
uint32_t hostlong, netlong;
hostlong = 0x12345678 ;
netlong = htonl( hostlong );
send(conn, &netlong, sizeof(netlong), 0);
snprintf()/strtol()
snprintf() で文字列に直して送り、strtol() や atoi() でもどす方法もある。
文字列文化。インターネットのアプリケーションでよく使われる。
送信側:
char buf[BUFSIZE];
hostlong = 0x12345678 ;
snprintf(buf,BUFSIZE,"%d\n",hostlong );
send(conn, buf, strlen(buf), 0);
思ったほど遅くはない。
注意:sscanf() は、整数をデコードするために使う分には問題ないが、
文字列を受け取るために使うとバッファ・オーバーフローが生じる可能性があるので、
使わない方がよい。
文字列のmarshaling
- 文字コードを合わせる。
- 複数バイトの場合、バイト・オーダも合わせる。
Last updated: 2024/06/27 15:02:10
Yasushi Shinjo / <yas@cs.tsukuba.ac.jp>