Я разрабатываю сетевое приложение с использованием Winsock API. Всякий раз, когда я проверяю приложение на отправку нескольких байтов, например, в массив:
char[0] = '1';
char[1] = '2';
char[2] = '3';
char[3] = '4';
char[4] = '\0';
Я использую send и recv socket для приема байтов в другом приложении, запущенном на localhost, тогда порядок байтов вообще не изменяется. Это просто потому, что я тестирую его на сервере localhost? Будет ли порядок байтов сети изменяться следующим образом:
char[0] = '\0';
char[1] = '4';
char[2] = '3';
char[3] = '2';
char[4] = '1';
если я получу его через Интернет?
8-разрядные массивы символов и строки не попадают в проблемы с порядком байтов сети. Поскольку каждый отдельный символ в массиве уже в порядке с самим собой и упорядочен со следующим байтом символа в массиве... Это короткие, ints и longs, которые оказываются затронутыми.
Кроме того, это не вызовы отправки и recv, которые выполняют любую байтовую подкачку. Обмен байтов связан с тем, как процессор выделяет целые числа в памяти:
Чтобы понять проблемы порядка байтов, рассмотрите следующий код на чипе Intel:
// code that demonstrates how integer values are laid out in memory
int msg = 0x01020304;
char* buffer = (char*)&msg;
for (int x = 0; x < 4; x++)
printf("%d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3]);
Результат, который распечатывается:
4 3 2 1
Это показывает, что процессоры x86 упорядочивают байты памяти целых чисел в противоположном порядке, который вы могли бы ожидать. Наименее значащий байт или целое число сначала упорядочивается в памяти. Это Маленький Эндиан.
На чипе Sparc, таком как старая рабочая станция Sun, этот же код печатает:
1 2 3 4
Это Большой Эндиан.
Это только при выводе данных на диск или в сеть, что имеет значение Endianness последовательности памяти. Как только другой компьютер считывает последовательность байтов, выписанную другим компьютером, тогда ЦП, считывающее целое число, будет интерпретировать его на основе собственной сущности.
Обычно при определении целых чисел для передачи файлов или потоковой передачи в сеть обычно имеет значение Endianness. Без преобразования разработчиком приложения необработанный буфер, переданный send(), передается точно так же, как процессор выдает байты в памяти. См. Htonl и friends для получения дополнительной информации о преобразовании целых чисел и коротких сообщений в и из Big Endian (также как порядок байтов сети).
i = 256;
Мне нужно преобразовать его в массив символов и передать буфер в сокет. Итак, откуда же в этом дело?
int j = htonl(i); send(sock, (char*)&j, sizeof(j), 0);
Аналогично, сделайте вызов ntohl () для полученного целого числа при получении его обратно.
Endianness только вступает в игру, когда вы смотрите на поток байтов и решаете интерпретировать данные.
Например, если у вас есть поток байтов:
'1' '2' '3' '4' '0'
И вы решили интерпретировать данные как поток символов, тогда, предполагая один байт на символ, у вас есть массив, содержащий строку "1234".
Однако, если вы решите интерпретировать данные как int
то вступает в действие утверждение, поскольку вы используете более одного байта, которые используются для кодирования типа данных (int). Значения вышеуказанного потока имеют шестнадцатеричные значения:
0x31 0x32 0x33 0x34 0x00
(0x31 - это шестнадцатеричное значение "1" и т.д.)
Именно здесь вступает в действие континент. Вам необходимо знать достоверность данных в потоке, чтобы вы могли успешно преобразовать их обратно в нужное значение при десериализации.
int i = 256;
Мне нужно преобразовать его в массив символов и передать буфер в сокет. Так откуда же в этом дело Endianness?
int
вы можете преобразовать его в сетевой порядок байтов, используя htonl
( msdn.microsoft.com/en-us/library/windows/desktop/… ). Затем, когда вы читаете его обратно, используйте ntohl
( msdn.microsoft.com/en-us/library/windows/desktop/… )
char
которые являются однобайтовыми, поэтому их нельзя переставить. Дело не в том, что весь твой поток переупорядочен. Я не уверен в этом, так что подтверждение было бы неплохо.