Перво-наперво, знаете, что такое связанный список ? Если вы понимаете это, вы узнаете, что происходит с циклом for. p
- указатель на структуру, которая также ссылается ( links ) на следующую структуру в списке. Итак, вы просматриваете список тех структур, которые являются addrinfo
структурами. 4
Теперь, что вам нужно знать о сетевых пакетах, так это то, что они состоят из заголовка. В частности, Ethernet frame . Это аппаратный протокол. Он позволяет вам работать в физической ограниченной сети, но ничего не знает о маршрутизации через границы физической сети.
Далее идет tcp или, возможно, другой протокол транспортного уровня, который находится где-то между двумя уровнями. TCP по сравнению с UDP и X по поводу того, как вы управляете пакетами - например, TCP требует, чтобы пакеты были собраны по порядку, в то время как UDP является протоколом «широковещательного» типа.
Наконец, у вас есть набор интернет-протоколов (IPv4, IPv6). Это протоколы более высокого уровня, которые контролируют более широкое понимание маршрутизации, поэтому они знают об Интернете в целом, но меньше знают о шагах, необходимых для его достижения.
Отличным объяснением этого является удобная диаграмма на этой странице . Чтобы завершить картину, BGP - это то, как маршрутизаторы знают, как перемещать вещи.
tcp / udp вписывается в эту картину, будучи частью (воплощенного в) рассматриваемого протокола (например, IPv4)
Таким образом, фреймы Ethernet содержат другие протоколы, прежде всего IPv4, которые содержат информацию, необходимую маршрутизаторам для передачи его через Интернет (через несколько физических сетей). Протокол internet указывает, куда вы хотите отправиться, откуда вы находитесь. Таким образом, тело типичного IPv4 остается неизменным на протяжении всего его транзита, но каждый раз, когда он пересекает физические сети, он упаковывается в другой пакет Ethernet.
Теперь в заголовке ethernet есть поле для поиска того, что содержит "тело ethernet". Эта строка:
if (p->ai_family == AF_INET) {
ли. AF_INET
- это константа, которая соответствует значению, которое tcp использует для идентификации тела пакета как IPv4. Итак, если вы смотрите на заголовок IPv4, этот цикл затем продолжает читать эту информацию.
Условие else является технически неправильным, потому что отсутствие IPv4 не делает его автоматически IPv6. Вы можете изменить его для проверки IPv6 следующим образом:
else if (p->ai_family == AF_INET6) {
Что вы, возможно, захотите сделать, на случай, если вы подберете что-нибудь еще.
Теперь стоит объяснить немного магии:
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
Это в основном принимает сетевую, или необработанную, форму данных, которые отображаются в виде последовательности байтов, и преобразует их (покрывает их) в поля структуры. Поскольку вы знаете, насколько большими будут поля, это очень быстрый и простой способ извлечь то, что вам нужно.
Последнее, что требует объяснения, это:
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
Есть и другие способы достижения этой цели, в частности ntohs()
.
В основном данные сети передаются в кодировке с прямым порядком байтов, и для их чтения необходимо (потенциально) преобразовать данные в кодировку вашей системы. Это может быть большой порядок байтов, или он может быть небольшим, это зависит от вашей системы по большей части. Прочитайте статью в Википедии о endianness .
Резюме: здесь вы видите комбинацию структур информатики, работы сетей и кода С.