Windows ソケット : バイトの順序付け
更新 : 2007 年 11 月
このトピックおよび関連する次の 2 つのトピックでは、Windows ソケット プログラミングについて説明します。ここでは、バイトの順序付けについて説明します。これ以外の問題については、「Windows ソケット : ブロッキング」および「Windows ソケット : 文字列の変換」を参照してください。
CAsyncSocket クラスを使うかこの派生クラスを使う場合は、上の処理を自分で管理する必要があります。CSocket を使うかその派生クラスを使う場合は、MFC が管理します。
バイトの順序付け
コンピュータのアーキテクチャが異なると、格納するデータのバイト順が異なることがあります。たとえば、Intel ベースのコンピュータにおけるデータの格納順は、Macintosh (Motorola) コンピュータの逆です。Intel のバイト順は "リトル エンディアン" と呼ばれ、ネットワーク標準の "ビッグ エンディアン" 順の逆です。これらの用語の意味は、次の表に示すとおりです。
ビッグ エンディアンとリトル エンディアンのバイト順
バイト順 |
説明 |
---|---|
ビッグ エンディアン |
ワードの左端が最上位バイトです。 |
リトル エンディアン |
ワードの右端が最上位バイトです。 |
通常、ネットワーク経由で送受信するデータのバイト順の変換は必要ありませんが、次のような場合はアプリケーション側でバイト順を変換する必要があります。
バイト順の変換が必要な場合
以下の場合はバイト順の変換が必要です。
別のコンピュータ宛のデータではなく、ネットワーク自体に解釈させる必要のある情報を渡すとき。たとえば、ネットワークが認識する必要のあるポートおよびアドレスを渡す場合。
通信相手のサーバー アプリケーションが MFC アプリケーションでなく、そのソース コードがないとき。両方のコンピュータが同一のバイト順でない場合
バイト順の変換が不要な場合
以下の場合は、バイト順の変換は不要です。
両端のコンピュータともバイトをスワップせず、両方のコンピュータが同一のバイト順を使っている場合。
通信相手のサーバーが MFC アプリケーションの場合。
通信相手のサーバーのソース コードがあり、バイト順の変換が必要かどうかを明示的に通知できる場合。
サーバーを MFC に移植できる場合。この移植は簡単であり、通常、移植後のコードはサイズ、速度の両方が向上します。
CAsyncSocket を使う場合は、必要なバイト順の変換を自分で管理する必要があります。Windows ソケットでは "ビッグ エンディアン" のバイト順モデルが標準なので、このバイト順とほかのバイト順の間の変換用関数が用意されています。ただし、CArchive は CSocket で使われるため、逆の順序である "リトル エンディアン" を使います。バイト順変換の詳細部分は CArchive が管理してくれます。アプリケーションでは、この標準バイト順を使うか、Windows ソケットのバイト順変換関数を使うと、移植性の高いコードになります。
MFC ソケットの理想的な使い方は、通信の両端を自分で作成し、両端に MFC を使う場合です。作成するアプリケーションの通信相手が FTP サーバーなどの非 MFC アプリケーションの場合は、データをアーカイブ オブジェクトに渡す前に、独自のバイト スワッピング管理が必要になることがあります。このバイト スワッピングには、Windows ソケット変換ルーチン ntohs、ntohl、htons、および htonl を使います。非 MFC アプリケーションとの通信に使うこれらの関数の例は、後で示します。
メモ : |
---|
通信相手が MFC アプリケーション以外の場合は、CObject から派生した C++ オブジェクトをアーカイブにストリーム転送しないでください。受信側では処理できません。「Windows ソケット : アーカイブ付きソケットの使用」のメモを参照してください。 |
バイト順の詳細については、Windows SDK で Windows ソケットの仕様を参照してください。
バイト順変換の例
次に示すのは、アーカイブを使用する CSocket オブジェクトのシリアル化関数の例です。Windows ソケット API におけるバイト順変換関数の使い方も説明します。
この例では、非 MFC サーバー アプリケーションと通信するクライアントを作成しています。このアプリケーションのソース コードにはアクセスできません。非 MFC サーバーは、ネットワークの標準バイト順を使うものとします。また、作成する MFC クライアント アプリケーションでは、CSocket オブジェクトと共に CArchive オブジェクトを使います。CArchive は "リトル エンディアン" バイト順を使うため、ネットワーク標準の逆になります。
通信相手の非 MFC サーバーでは、次のようなメッセージ パケット用プロトコルが設定されているものとします。
struct Message
{
long MagicNumber;
unsigned short Command;
short Param1;
long Param2;
};
これは、MFC では次のように表現されます。
struct Message
{
long m_lMagicNumber;
short m_nCommand;
short m_nParam1;
long m_lParam2;
void Serialize( CArchive& ar );
};
C++ では、struct は基本的にクラスと同じものです。構造体 Message は、上で宣言されている Serialize などのメンバ関数を持つことができます。メンバ関数 Serialize は次のようになります。
void Message::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << (DWORD)htonl(m_lMagicNumber);
ar << (WORD)htons(m_nCommand);
ar << (WORD)htons(m_nParam1);
ar << (DWORD)htonl(m_lParam2);
}
else
{
WORD w;
DWORD dw;
ar >> dw;
m_lMagicNumber = ntohl((long)dw);
ar >> w ;
m_nCommand = ntohs((short)w);
ar >> w;
m_nParam1 = ntohs((short)w);
ar >> dw;
m_lParam2 = ntohl((long)dw);
}
}
この例では、データのバイト順変換が必要です。非 MFC サーバー アプリケーションのバイト順が、相手側の MFC クライアント アプリケーションで使われている CArchive のバイト順と異なるからです。この例では、Windows ソケットのバイト順変換関数がいくつか使われています。次の表は、これらの関数についての説明です。
Windows ソケットのバイト順変換関数
関数 |
目的 |
---|---|
ntohs |
16 ビットの値をネットワークのバイト順からホストのバイト順に変換します (ビッグ エンディアンからリトル エンディアンに)。 |
ntohl |
32 ビットの値をネットワークのバイト順からホストのバイト順に変換します (ビッグ エンディアンからリトル エンディアンに)。 |
Htons |
16 ビットの値をホストのバイト順からネットワークのバイト順に変換します (リトル エンディアンからビッグ エンディアンに)。 |
Htonl |
32 ビットの値をホストのバイト順からネットワークのバイト順に変換します (リトル エンディアンからビッグ エンディアンに)。 |
この例のもう 1 つの特徴は、通信相手のソケット アプリケーションが非 MFC アプリケーションの場合に、次のような行を記述できない点です。
ar << pMsg;
pMsg は、CObject クラスから派生した C++ オブジェクトへのポインタです。この行はオブジェクトに関連する補足 MFC 情報を送信しますが、サーバーは MFC アプリケーションとは異なり、理解できません。
詳細については、次のトピックを参照してください。