Поделиться через


Сокеты Windows. Порядок байтов

В этой статье и двух дополнительных статьях объясняется несколько проблем программирования сокетов Windows. В этой статье рассматриваются упорядочение байтов. Другие проблемы рассматриваются в статьях: сокеты Windows: блокировка и сокеты Windows: преобразование строк.

Если вы используете или извлекаете из класса CAsyncSocket, вам потребуется самостоятельно управлять этими проблемами. При использовании или производных от класса CSocket MFC управляет ими.

Порядок байтов

Разные архитектуры компьютеров иногда хранят данные с помощью разных заказов байтов. Например, компьютеры на основе Intel хранят данные в обратном порядке компьютеров Macintosh (Motorola). Порядок байтов Intel, называемый "little-Endian", также является обратным порядком сети "big-Endian". В следующей таблице описаны эти термины.

Порядок больших и маленьких байтов

Порядок байтов Значение
Big-Endian Самый значительный байт находится в левом конце слова.
Маленький эндиан Самый значительный байт находится в правом конце слова.

Как правило, вам не нужно беспокоиться о преобразовании байтов для данных, которые вы отправляете и получаете по сети, но существуют ситуации, в которых необходимо преобразовать заказы байтов.

Когда необходимо преобразовать заказы байтов

В следующих ситуациях необходимо преобразовать заказы байтов:

  • Вы передаете информацию, которая должна интерпретироваться сетью, а не данные, отправляемые на другой компьютер. Например, можно передать порты и адреса, которые должны понимать сеть.

  • Серверное приложение, с которым вы взаимодействуете, не является приложением MFC (и у вас нет исходного кода). Это вызывает преобразования порядка байтов, если два компьютера не используют одинаковый порядок байтов.

Если вам не нужно преобразовывать заказы байтов

Вы можете избежать работы преобразования заказов байтов в следующих ситуациях:

  • Компьютеры на обоих концах могут не переключать байты, и оба компьютера используют одинаковый порядок байтов.

  • Сервер, с которым вы взаимодействуете, является приложением MFC.

  • У вас есть исходный код для сервера, с которым вы взаимодействуете, поэтому вы можете явно определить, нужно ли преобразовать заказы байтов или нет.

  • Сервер можно перенести в MFC. Это довольно легко сделать, и результат обычно меньше, быстрее кода.

Работая с CAsyncSocket, необходимо самостоятельно управлять любыми необходимыми преобразованиями порядка байтов. Сокеты Windows стандартизуют модель байтового порядка big-Endian и предоставляет функции для преобразования между этим порядком и другими. Однако CArchive, который вы используете с CSocket, использует противоположный порядок ("маленький эндиан"), но CArchive заботится о деталях преобразования байтов для вас. Используя этот стандартный порядок в приложениях или с помощью функций преобразования байтов в сокетах Windows, вы можете сделать код более переносимым.

Идеальным вариантом использования сокетов MFC является написание обоих окончаний взаимодействия: использование MFC в обоих концах. Если вы пишете приложение, которое будет взаимодействовать с приложениями, не являющихся MFC, например FTP-сервером, вам, вероятно, потребуется самостоятельно управлять переключениями байтов перед передачей данных в архивный объект, используя подпрограммы преобразования сокетов Windows ntohs, ntohl, htons и htonl. Пример этих функций, используемых в взаимодействии с приложением, отличным от MFC, отображается далее в этой статье.

Примечание.

Если другой конец связи не является приложением MFC, необходимо также избежать потоковой передачи объектов C++, производных от CObject архива, так как получатель не сможет обрабатывать их. См. примечание в сокетах Windows: использование сокетов с архивами.

Дополнительные сведения о заказах байтов см. в спецификации сокетов Windows, доступной в пакете SDK для Windows.

Пример преобразования байтового порядка

В следующем примере показана функция сериализации для CSocket объекта, использующего архив. Он также иллюстрирует использование функций преобразования байтов в API сокетов Windows.

В этом примере представлен сценарий, в котором вы пишете клиент, который взаимодействует с серверным приложением, отличным от MFC, для которого у вас нет доступа к исходному коду. В этом сценарии необходимо предположить, что сервер, отличный от MFC, использует стандартный порядок байтов сети. В отличие от этого, клиентское приложение MFC использует объект с CSocket объектом и CArchive использует CArchive байтовый порядок "little-Endian", противоположность стандарту сети.

Предположим, что сервер, отличный от 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, в одном конце и CArchive используемым в клиентском приложении MFC в другом конце. В этом примере показано несколько функций преобразования байтов, предоставляемых сокетами Windows. В следующей таблице описаны эти функции.

Функции преобразования сокетов Windows Byte-Order

Функция Назначение
ntohs Преобразование 16-разрядного количества из сетевого байтового порядка в порядок байтов узла (big-Endian в маленький эндиан).
ntohl Преобразование 32-разрядного количества из байтов сети в порядок байтов узла (big-Endian в маленький эндиан).
Хтоны Преобразование 16-разрядного количества из порядка байтов узла в сетевой порядок байтов (маленький байт в big-Endian).
Htonl Преобразование 32-разрядного количества из порядка байтов узла в сетевой байтовый порядок (маленький байт в big-Endian).

Еще одна точка этого примера заключается в том, что если приложение сокета в другом конце связи — это приложение, отличное от MFC, необходимо избежать выполнения следующих действий:

ar << pMsg;

где pMsg указатель на объект C++, производный от класса CObject. Это приведет к отправке дополнительных сведений MFC, связанных с объектами, и сервер не поймет его, так как это было бы, если бы это было приложение MFC.

Дополнительные сведения см. в разделе:

См. также

Сокеты Windows в MFC