Windows ソケット : バイトの順序付け
この記事と 2 つの関連記事では、Windows ソケット プログラミングにおけるいくつかの問題について説明します。 この記事では、バイト順について説明します。 その他の問題については、「Windows ソケット: ブロッキング」と「Windows ソケット: 文字列の変換」という記事で説明されています。
CAsyncSocket クラスを使用するか、このクラスから派生させる場合は、これらの問題を自分で管理する必要があります。 CSocket クラスを使用するか、このクラスから派生させる場合は、これらの問題が MFC によって管理されます。
バイトの順序付け
異なるコンピューター アーキテクチャでは、異なるバイト順を使用してデータを格納する場合があります。 たとえば、Intel ベースのコンピューターでは、Macintosh (Motorola) コンピューターの逆の順序でデータが保存されます。 "リトルエンディアン" と呼ばれる Intel のバイト順も、ネットワークの標準の "ビッグエンディアン" の順序と逆になります。 これらの用語について、次の表で説明します。
ビッグエンディアンとリトルエンディアンのバイト順
バイトの順序付け | 意味 |
---|---|
ビッグエンディアン | 最上位バイトは単語の左端にあります。 |
リトルエンディアン | 最上位バイトは単語の右端にあります。 |
通常、ネットワーク経由で送受信されるデータのバイト順の変換について心配する必要はありませんが、バイト順を変換するしなければならない場合があります。
バイト順を変換する必要がある場合
次の状況では、バイト順を変換する必要があります。
別のコンピューターに送信するデータではなく、ネットワークによって解釈される必要がある情報を渡しています。 たとえば、ネットワークが認識する必要があるポートとアドレスを渡すことができます。
通信中のサーバー アプリケーションは、MFC アプリケーションではありません (ソースコードはありません)。 2 台のコンピューターが同じバイト順を共有していない場合、バイト順の変換が呼び出されます。
バイト順を変換する必要がない場合
次の状況では、バイト順の変換作業を回避できます:
両端のマシンは、バイトをスワップしないことに同意し、両方のコンピューターが同じバイト順を使用します。
通信しているサーバーは MFC アプリケーションです。
通信しているサーバーのソース コードがあるため、バイト順を変換する必要があるかどうかを明示的に判断できます。
サーバーを MFC に移植できます。 これは非常に簡単です。通常、結果のコードはより小さく、より高速になります。
CAsyncSocket を使用する場合は、必要なバイト順変換を自分で管理する必要があります。 Windows ソケットは、"ビッグエンディアン" バイト順モデルを標準化し、この順序と他の順序の間で変換を行う関数を提供します。 ただし、CSocket で使用する CArchive は、逆の ("リトルエンディアン") 順序を使用しますが、CArchive
ではバイト順変換の詳細に対処します。 アプリケーションでこの標準の順序付けを使用するか、Windows ソケットのバイト順変換関数を使用することにより、コードの移植性を高めることができます。
MFC ソケットの理想的な使用状況は、通信の両端を自分で作成し、両端で MFC を使用する場合です。 FTP サーバーなど、非 MFC アプリケーションと通信するアプリケーションを作成する場合は、Windows ソケット変換ルーチンntohs、 ntohl、 htons、および htonlを使用してアーカイブ オブジェクトにデータを渡す前に、バイト スワップを自分で管理する必要があります。 MFC 以外のアプリケーションとの通信で使用されるこれらの関数の例については、この記事の後半で説明します。
Note
通信の相手側が MFC アプリケーションでない場合は、CObject
から派生した C++ オブジェクトを受信側がそれを処理できないのでアーカイブに保存しないようにする必要もあります。 「Windows ソケット: アーカイブ付きソケットの使用」を参照してください。
バイト順の詳細については、Windows SDK 同梱されている Windows ソケットの仕様書を参照してください。
バイト順変換の例
次の例は、アーカイブを使用する CSocket
オブジェクトのシリアル化関数を示しています。 また、Windows Sockets 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 アプリケーションの場合と同様に、サーバーでは認識されません。
詳細については、以下を参照してください: