Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье и двух дополнительных статьях объясняется несколько проблем программирования сокетов Windows. В этой статье рассматривается упорядочение байтов. Другие проблемы рассматриваются в статьях: сокеты Windows: блокировка и сокеты Windows: преобразование строк.
Если вы используете или извлекаете из класса CAsyncSocket, вам потребуется самостоятельно управлять этими проблемами. При использовании класса или наследовании от CSocket, MFC управляет ими для вас.
Порядок байтов
Разные архитектуры компьютеров иногда хранят данные в разных порядках байтов. Например, компьютеры на основе Intel хранят данные в обратном порядке компьютеров Macintosh (Motorola). Порядок байтов Intel, называемый "little-Endian", также отличается от сетевого стандарта "big-Endian". В следующей таблице описаны эти термины.
Порядок больших и Little-Endian байтов
Упорядочение байтов | Значение |
---|---|
Big-Endian | Самый значительный байт находится в левом конце слова. |
Little-Endian | Самый значительный байт находится в правом конце слова. |
Как правило, вам не нужно беспокоиться о преобразовании порядка байтов для данных, которые вы отправляете и получаете по сети, но существуют ситуации, в которых необходимо преобразовать порядок байтов.
Когда необходимо преобразовать порядок байтов
В следующих ситуациях необходимо изменить порядок байтов:
Вы передаете информацию, которая должна интерпретироваться сетью, а не данные, отправляемые на другой компьютер. Например, можно передать порты и адреса, которые должны понимать сеть.
Серверное приложение, с которым вы взаимодействуете, не является приложением MFC (и у вас нет исходного кода). Это вызывает преобразования порядка байтов, если два компьютера не используют одинаковый порядок байтов.
Когда не нужно преобразовывать порядок байтов
Вы можете избежать необходимости преобразования порядков байтов в следующих ситуациях:
Компьютеры на обоих концах могут не переключать байты, и оба компьютера используют одинаковый порядок байтов.
Сервер, с которым вы взаимодействуете, является приложением MFC.
У вас есть исходный код для сервера, с которым вы взаимодействуете, поэтому вы можете явно определить, нужно ли преобразовать заказы байтов или нет.
Сервер можно перенести в MFC. Это довольно легко сделать, и результатом обычно является компактный и быстрый код.
Работая с CAsyncSocket, необходимо самостоятельно управлять любыми необходимыми преобразованиями порядка байтов. Windows Sockets стандартизуют модель байтового порядка "big-Endian" и предоставляют функции для преобразования между этим порядком и другими.
Однако CArchive, который вы используете с CSocket, использует противоположный порядок ("маленький эндиан"), но CArchive
обрабатывает детали преобразования порядка байтов для вас. Используя этот стандартный порядок в приложениях или с помощью функций преобразования байтов в сокетах Windows, вы можете сделать код более переносимым.
Идеальным вариантом использования сокетов MFC является случай, когда вы разрабатываете оба конца взаимодействия, используя MFC. Если вы пишете приложение, которое будет взаимодействовать с приложениями, не являющихся MFC, например FTP-сервером, вам, вероятно, потребуется самостоятельно управлять переключениями байтов перед передачей данных в архивный объект, используя подпрограммы преобразования сокетов Windows ntohs, ntohl, htons и htonl. Пример этих функций, используемых в взаимодействии с приложением, отличным от MFC, отображается далее в этой статье.
Замечание
Если другой конец связи не является приложением MFC, необходимо также избежать потоковой передачи объектов C++, производных от CObject
архива, так как получатель не сможет обрабатывать их. См. примечание в Windows Sockets: Использование сокетов с архивами.
Дополнительные сведения о порядке байтов см. в спецификации Windows Sockets, доступной в пакете Windows SDK.
Пример преобразования Byte-Order
В следующем примере показана функция сериализации для CSocket
объекта, использующего архив. Он также иллюстрирует использование функций преобразования порядка байтов в API сокетов Windows.
В этом примере представлен сценарий, в котором вы пишете клиент, который взаимодействует с серверным приложением, отличным от MFC, для которого у вас нет доступа к исходному коду. В этом сценарии необходимо предположить, что сервер, отличный от MFC, использует стандартный порядок байтов сети. В отличие от этого, ваше клиентское приложение MFC использует объект CArchive
вместе с объектом CSocket
, и 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 к little-endian). |
Хтоны | Преобразовать 16-разрядное число из порядка байтов узла в сетевой порядок байтов (младший байт в старший байт). |
Htonl | Преобразование 32-разрядного количества из порядка байтов узла в сетевой байтовый порядок (маленький байт в big-Endian). |
Еще одним аспектом этого примера является то, что если приложение сокета на противоположной стороне соединения не использует MFC, необходимо избегать подобных действий, как указано ниже:
ar << pMsg;
где pMsg
указатель на объект C++, производный от класса CObject
. Это приведет к отправке дополнительных сведений о MFC, связанных с объектами, и сервер не сможет их понять так, как понимал бы, если бы это было приложение MFC.
Дополнительные сведения можно найти здесь