Я только начал на каком-то простом сетевом программировании на C ++ и собирал на моем Raspberry Pi (без кросс-компиляции). Это делает все немного прямым
После создания заголовка IP я вычисляю контрольную сумму IP, но она всегда получалась неправильной (на примере здесь http://www.thegeekstuff.com/2012/05/ip-header-checksum/).
Обращаясь к gdb, я решил проблему до порядка первых 32 бит в заголовке IP. В примере используются 0x4500003C
, что означает версию 4 (0x4
), МГП 5 (0x5
), TOS 0 (0x00
) и общая длина 60 (0x003C
). Поэтому я настроил свой пакет так же.
struct iphdr* ip; // Also some mallocing
ip->version = 4;
ip->ihl = 5;
ip->tos = 0;
ip->tot_len = 60;
Сейчас в gdb я изучил первые 32 бита, ожидая 0x3C000045
из-за порядка байтов, но вместо этого я получаю это:
(gdb) print ip
$1 = (iphdr *) 0x11018
(gdb) x/1xw 0x11018
0x11018: 0x003c0045
Первые 16 битов находятся в порядке байтов (0x0045
) но вторая, содержащая десятичную 60, кажется, в старшем порядке (0x003C
)!
Что дает это? Я сумасшедший? Я совершенно не прав насчет порядка байтов внутри структур? (Это определенная возможность)
В структуре есть порядок полей, а в многобайтовом поле — порядок байтов.
0x003C
это вовсе не endian, это шестнадцатеричное значение для 60. Конечно, оно хранится в памяти с некоторым порядком байтов, но порядок, который вы использовали для записи поля, и порядок, который вы использовали для его чтения, одинаковы — оба родной порядок байтов Raspberry Pi, и они отменяются.
Обычно вы хотите написать:
ip->tot_len = htons(60);
при сохранении 16-битного поля в пакет. Есть также htonl
для 32-битных полей и ntohs
а также ntohl
для чтения полей из сетевых пакетов.
Архитектура ARM может работать как с прямым, так и с малым порядком байтов, но платформа Android работает с прямым порядком байтов.