Udostępnij za pośrednictwem


Windows Sockets: określanie kolejności bajtów

W tym artykule i dwóch artykułach towarzyszących opisano kilka problemów z programowaniem windows Sockets. W tym artykule opisano kolejność bajtów. Inne problemy zostały omówione w artykułach: Windows Sockets: Blocking and Windows Sockets: Converting Strings (Blokowanie i gniazda systemu Windows: konwertowanie ciągów).

Jeśli używasz lub pochodzisz z klasy CAsyncSocket, musisz samodzielnie zarządzać tymi problemami. Jeśli używasz lub pochodzisz z klasy CSocket, MFC zarządza nimi za Ciebie.

określanie kolejności bajtów

Różne architektury maszyn czasami przechowują dane przy użyciu różnych zamówień bajtów. Na przykład maszyny firmy Intel przechowują dane w odwrotnej kolejności komputerów Macintosh (Macintosh). Kolejność bajtów Intel, nazywana "little-Endian", jest również odwrotną kolejnością standardu sieci "big-Endian". W poniższej tabeli opisano te terminy.

Porządkowanie bajtów big- i little-endian

określanie kolejności bajtów Znaczenie
Big-Endian Najbardziej znaczący bajt znajduje się na lewym końcu słowa.
Little-Endian Najbardziej znaczący bajt znajduje się na prawym końcu słowa.

Zazwyczaj nie trzeba martwić się o konwersję kolejności bajtów dla danych, które wysyłasz i odbierasz za pośrednictwem sieci, ale istnieją sytuacje, w których należy przekonwertować zamówienia bajtów.

Kiedy należy przekonwertować zamówienia bajtów

Należy przekonwertować zamówienia bajtów w następujących sytuacjach:

  • Przekazujesz informacje, które muszą być interpretowane przez sieć, w przeciwieństwie do danych wysyłanych do innej maszyny. Na przykład możesz przekazać porty i adresy, które sieć musi zrozumieć.

  • Aplikacja serwera, z którą się komunikujesz, nie jest aplikacją MFC (i nie masz dla niej kodu źródłowego). Spowoduje to wywołanie konwersji kolejności bajtów, jeśli obie maszyny nie współużytkują tej samej kolejności bajtów.

Jeśli nie musisz konwertować zamówień bajtów

W następujących sytuacjach można uniknąć pracy z konwertowaniem zamówień bajtów:

  • Maszyny na obu końcach mogą nie zgadzać się na zamianę bajtów, a obie maszyny używają tej samej kolejności bajtów.

  • Serwer, z którym komunikujesz się, to aplikacja MFC.

  • Masz kod źródłowy dla serwera, z którym komunikujesz się, więc możesz jawnie określić, czy należy przekonwertować zamówienia bajtów, czy nie.

  • Serwer można przenosić do MFC. Jest to dość łatwe do zrobienia, a wynik jest zwykle mniejszy, szybszy.

Praca z narzędziem CAsyncSocket wymaga samodzielnego zarządzania niezbędnymi konwersjami zamówień bajtów. Windows Sockets standandaryzuje model "big-Endian" byte-order i udostępnia funkcje do konwersji między tą kolejnością a innymi. CArchive, jednak używany z CSocket, używa odwrotnej kolejności ("little-Endian"), ale CArchive zajmuje się szczegółami konwersji zamówień bajtów. Korzystając z tej standardowej kolejności w aplikacjach lub korzystając z funkcji konwersji zamówień bajtów gniazd systemu Windows, możesz zwiększyć przenośność kodu.

Idealny przypadek użycia gniazd MFC polega na pisaniu obu końców komunikacji: przy użyciu MFC na obu końcach. Jeśli piszesz aplikację, która będzie komunikować się z aplikacjami innych niż MFC, takich jak serwer FTP, prawdopodobnie musisz zarządzać zamianą bajtów samodzielnie przed przekazaniem danych do obiektu archiwum przy użyciu procedur konwersji gniazd systemu Windows ntohs, ntohl, htons i htonl. Przykład tych funkcji używanych w komunikacji z aplikacją inną niż MFC pojawia się w dalszej części tego artykułu.

Uwaga

Gdy drugi koniec komunikacji nie jest aplikacją MFC, należy również unikać przesyłania strumieniowego obiektów języka C++ pochodzących z CObject archiwum, ponieważ odbiornik nie będzie mógł ich obsłużyć. Zobacz uwagę w temacie Windows Sockets: Using Sockets with Archives (Używanie gniazd z archiwami).

Aby uzyskać więcej informacji na temat zamówień bajtów, zobacz specyfikację gniazd systemu Windows dostępną w zestawie Windows SDK.

Przykład konwersji kolejności bajtów

W poniższym przykładzie przedstawiono funkcję serializacji dla CSocket obiektu korzystającego z archiwum. Ilustruje również użycie funkcji konwersji kolejności bajtów w interfejsie API gniazd systemu Windows.

W tym przykładzie przedstawiono scenariusz, w którym piszesz klienta komunikującego się z aplikacją serwera innego niż MFC, dla którego nie masz dostępu do kodu źródłowego. W tym scenariuszu należy założyć, że serwer inny niż MFC używa standardowej kolejności bajtów sieciowych. Natomiast aplikacja kliencka MFC używa CArchive obiektu z obiektem CSocket i CArchive używa kolejności bajtów "little-Endian", odwrotnie niż w przypadku standardu sieciowego.

Załóżmy, że serwer inny niż MFC, za pomocą którego planujesz komunikować się, ma ustanowiony protokół dla pakietu komunikatów, jak pokazano poniżej:

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

W kategoriach MFC byłoby to wyrażone w następujący sposób:

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

   void Serialize(CArchive &ar);
};

W języku C++element jest struct zasadniczo taki sam jak klasa. Struktura Message może mieć funkcje składowe, takie jak Serialize funkcja składowa zadeklarowana powyżej. Funkcja Serialize składowa może wyglądać następująco:

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

W tym przykładzie jest wywoływana konwersja danych w kolejności bajtów, ponieważ istnieje wyraźna niezgodność między kolejnością bajtów aplikacji serwera innego niż MFC na jednym końcu i CArchive używanymi w aplikacji klienckiej MFC na drugim końcu. W przykładzie pokazano kilka funkcji konwersji bajtów, które dostarcza windows Sockets. W poniższej tabeli opisano te funkcje.

Funkcje konwersji zamówień bajtów gniazd systemu Windows

Function Cel
ntohs Przekonwertuj 16-bitową ilość z kolejności bajtów sieciowych na kolejność bajtów hostowania (big-Endian na little-Endian).
ntohl Przekonwertuj ilość 32-bitową z kolejności bajtów sieciowych na kolejność bajtów hosta (big-Endian na little-Endian).
Wtony Przekonwertuj 16-bitową ilość z kolejności bajtów hosta na kolejność bajtów sieciowych (little-Endian na big-Endian).
Htonl Przekonwertuj ilość 32-bitową z kolejności bajtów hosta na kolejność bajtów sieciowych (little-Endian na big-Endian).

Innym punktem tego przykładu jest to, że gdy aplikacja gniazda na drugim końcu komunikacji jest aplikacją inną niż MFC, należy unikać wykonywania czynności podobnych do następujących:

ar << pMsg;

gdzie pMsg jest wskaźnikiem do obiektu C++ pochodzącego z klasy CObject. Spowoduje to wysłanie dodatkowych informacji MFC skojarzonych z obiektami i serwer nie będzie go rozumieć, tak jak gdyby była to aplikacja MFC.

Aby uzyskać więcej informacji, zobacz:

Zobacz też

Gniazda systemu Windows w MFC