Udostępnij za pośrednictwem


Windows Sockets: Porządkowanie 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 oraz Windows Sockets: Converting Strings.

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.

Porządkowanie bajtów

Różne architektury maszyn czasami przechowują dane z użyciem różnych kolejności bajtów. Na przykład maszyny Intel przechowują dane w odwrotnej kolejności niż komputery Macintosh (Motorola). Kolejność bajtów Intel, nazywana „little-Endian”, jest również odwrotnością standardowej kolejności sieciowej „big-Endian”. W poniższej tabeli opisano te terminy.

Porządkowanie bajtów dużych i Little-Endian

Porządkowanie 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 musisz martwić się o konwersję kolejności bajtów dla danych, które wysyłasz i odbierasz za pośrednictwem sieci, ale są sytuacje, w których musisz przekonwertować kolejność bajtów.

Kiedy należy przekonwertować kolejność bajtów

Należy przekonwertować kolejność 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). Wywołuje to konieczność konwersji kolejności bajtów, jeśli dwie maszyny nie używają tej samej kolejności bajtów.

Kiedy nie musisz konwertować kolejności bajtów

W następujących sytuacjach można uniknąć pracy nad konwertowaniem porządku 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 się komunikujesz, więc możesz jawnie określić, czy musisz zmienić kolejność bajtów, czy nie.

  • Serwer można przenosić do MFC. Stosunkowo łatwo to zrobić, a kod wynikowy jest zwykle mniejszy i szybszy.

Praca z CAsyncSocket wymaga samodzielnego zarządzania niezbędnymi konwersjami kolejności bajtów. Windows Sockets standaryzuje model porządkowania bajtów "big-Endian" i udostępnia funkcje do konwersji między tym porządkiem a innymi. CArchive, jednak używany z CSocket, używa odwrotnej kolejności ("little-Endian"), ale CArchive zajmuje się szczegółami konwersji kolejności bajtów. Korzystając z standardowego porządkowania w aplikacjach lub korzystając z funkcji konwersji kolejności bajtów w gniazdach systemu Windows, możesz zwiększyć przenośność kodu.

Najlepszy przypadek użycia gniazd MFC to pisanie obu końców komunikacji, poprzez użycie 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 / Notatka

Gdy druga strona komunikacji nie jest aplikacją MFC, należy również unikać przesyłania strumieniowego obiektów C++ pochodzących z CObject do swojego archiwum, ponieważ odbiorca nie będzie w stanie 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 kolejności bajtów, zobacz specyfikację Windows Sockets dostępną w zestawie Windows SDK.

Przykład konwersji Byte-Order

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, w przeciwieństwie do standardu sieciowego, aplikacja kliencka MFC używa obiektu CArchive z obiektem CSocket, a CArchive stosuje kolejność bajtów "little-Endian".

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 sposób następujący:

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

   void Serialize(CArchive &ar);
};

W języku C++ struct jest 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 konieczne są konwersje kolejności bajtów danych, ponieważ istnieje wyraźna niezgodność między kolejnością bajtów aplikacji serwerowej innej niż MFC z jednej strony a CArchive użytych w aplikacji klienckiej MFC z drugiej strony. Przykład ilustruje kilka funkcji konwersji porządku bajtów, które dostarcza Windows Sockets. W poniższej tabeli opisano te funkcje.

Funkcje konwersji gniazd Windows Byte-Order

Funkcja Przeznaczenie
ntohs Przekonwertuj 16-bitową wartość z kolejności bajtów sieciowych na kolejność bajtów hosta (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ą wartość z kolejności bajtów hosta na kolejność bajtów sieciowych (little-Endian na big-Endian).
Htonl Przekonwertuj 32-bitową wartość z porządku bajtów hosta na porządek bajtów sieciowych (z *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 także

Windows Sockets w MFC