Sdílet prostřednictvím


Windows Sockets: Pořadí bajtů

Tento článek a dva doprovodné články vysvětlují několik problémů s programováním rozhraní Windows Sockets. Tento článek se zabývá řazením bajtů. Další problémy jsou popsané v článcích: Windows Sockets: Blocking a Windows Sockets: Převod řetězců.

Pokud používáte nebo odvozujete z třídy CAsyncSocket, budete muset tyto problémy spravovat sami. Pokud používáte nebo odvozujete třídu CSocket, MFC je spravuje za vás.

Pořadí bajtů

Různé architektury počítačů někdy ukládají data pomocí různých bajtů objednávek. Například počítače založené na technologii Intel ukládají data v obráceném pořadí počítačů Macintosh (Motorola). Pořadí bajtů Intel, označované jako "little-Endian", je také opačnou součástí standardního pořadí "big-Endian". Následující tabulka vysvětluje tyto termíny.

Řazení velkých a malých endiánských bajtů

Pořadí bajtů Význam
Big-Endian Nejvýznamnější bajt je na levém konci slova.
Little-Endian Nejvýznamnější bajt je na pravém konci slova.

Obvykle si nemusíte dělat starosti s převodem bajtů pro data, která odesíláte a přijímáte přes síť, ale existují situace, kdy je nutné převést bajtové objednávky.

Když je nutné převést bajtové objednávky

V následujících situacích je potřeba převést bajtové objednávky:

  • Předáváte informace, které je potřeba interpretovat sítí, na rozdíl od dat, která odesíláte do jiného počítače. Můžete například předat porty a adresy, kterým musí síť rozumět.

  • Serverová aplikace, se kterou komunikujete, není aplikací MFC (a pro ni nemáte zdrojový kód). To volá převody pořadí bajtů, pokud tyto dva počítače nesdílejí stejné pořadí bajtů.

Pokud není nutné převádět bajtové objednávky

V následujících situacích se můžete vyhnout převodu bajtů:

  • Počítače na obou koncích mohou souhlasit s tím, že neprohodí bajty, a oba počítače používají stejné pořadí bajtů.

  • Server, se kterým komunikujete, je aplikace MFC.

  • Máte zdrojový kód pro server, se kterým komunikujete, takže můžete explicitně zjistit, jestli je nutné převést objednávky bajtů, nebo ne.

  • Server můžete přenést do knihovny MFC. To je poměrně snadné a výsledek je obvykle menší, rychlejší kód.

Při práci s CAsyncSocket musíte spravovat všechny potřebné převody bajtů sami. Windows Sockets standardizuje model "big-Endian" bajtů a poskytuje funkce pro převod mezi tímto pořadím a ostatními. CArchive, který však používáte s CSocket, používá opačné pořadí ("little-Endian"), ale CArchive stará se o podrobnosti převodů bajtů za vás. Pomocí tohoto standardního řazení v aplikacích nebo pomocí funkcí převodu bajtů windows Sockets můžete kód usnadnit.

Ideálním případem použití soketů knihovny MFC je, když vytváříte obě strany komunikace: používáte knihovnu MFC na obou koncích. Pokud píšete aplikaci, která bude komunikovat s aplikacemi jiných než MFC, jako je třeba server FTP, budete pravděpodobně muset spravovat bajtové prohození sami před předáním dat do archivního objektu pomocí rutin převodu Windows Sockets ntohs, ntohl, htons a htonl. Příklad těchto funkcí používaných při komunikaci s aplikací mimo MFC se zobrazí dále v tomto článku.

Poznámka

Pokud druhý konec komunikace není aplikace MFC, musíte se vyhnout streamování objektů C++ odvozených z CObject archivu, protože příjemce je nebude schopen zpracovat. Podívejte se na poznámku v rozhraní Windows Sockets: Použití soketů s archivy.

Další informace o objednávkách bajtů naleznete ve specifikaci Windows Sockets, která je k dispozici v sadě Windows SDK.

Příklad převodu bajtů

Následující příklad ukazuje serializační funkci pro CSocket objekt, který používá archiv. Ukazuje také použití funkcí převodu bajtů v rozhraní API rozhraní Windows Sockets.

Tento příklad představuje scénář, ve kterém píšete klienta, který komunikuje s serverovou aplikací mimo MFC, pro kterou nemáte přístup ke zdrojovému kódu. V tomto scénáři je nutné předpokládat, že server jiného typu než MFC používá standardní pořadí bajtů sítě. Naproti tomu klientská aplikace MFC používá CArchive objekt s objektem CSocket a CArchive používá pořadí bajtů "little-Endian", tedy opak síťového standardu.

Předpokládejme, že server jiného typu než MFC, se kterým chcete komunikovat, má vytvořený protokol pro paket zprávy, například následující:

struct Message
{
   long MagicNumber;
   unsigned short Command;
   short Param1;
   long Param2;
};

V prostředí MFC by to bylo vyjádřeno takto:

struct Message
{
   long m_lMagicNumber;
   short m_nCommand;
   short m_nParam1;
   long m_lParam2;

   void Serialize(CArchive &ar);
};

V jazyce C++ struct je v podstatě totéž jako třída. Struktura Message může mít členské funkce, jako Serialize je například členová funkce deklarovaná výše. Členová Serialize funkce může vypadat takto:

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);
   }
}

Tento příklad volá převody dat podle pořadí bajtů, protože došlo k jasné neshodě mezi pořadím bajtů serverové aplikace jiné než MFC na jednom konci a CArchive použitým v klientské aplikaci MFC na druhém konci. Příklad znázorňuje několik funkcí převodu bajtů, které windows Sockets poskytuje. Následující tabulka popisuje tyto funkce.

Funkce převodu bajtů Windows Sockets

Function Purpose
ntohs Převede 16bitové množství z pořadí bajtů sítě na pořadí bajtů hostitele (big-Endian na little-Endian).
ntohl Převede 32bitové množství z pořadí bajtů sítě na pořadí bajtů hostitele (big-Endian na little-Endian).
Htons Převede 16bitové množství z pořadí bajtů hostitele na pořadí bajtů sítě (little-Endian na big-Endian).
Htonl Převede 32bitové množství z pořadí bajtů hostitele na pořadí bajtů sítě (little-Endian na big-Endian).

Dalším bodem tohoto příkladu je to, že když je aplikace soketu na druhém konci komunikace aplikace mimo MFC, musíte se vyhnout následujícímu:

ar << pMsg;

where pMsg je ukazatel na objekt C++ odvozený z třídy CObject. Tím se odešlou další informace MFC přidružené k objektům a server mu nerozumí, stejně jako kdyby šlo o aplikaci MFC.

Další informace naleznete v tématu:

Viz také

Windows Sockets v prostředí MFC