Почему мы можем использовать sockaddr для sockaddr_in?

Я вижу, почему полезно отбрасывать sockaddr в sockaddr_in, но я не понимаю, как это возможно. Из того, что я читал, они имеют одинаковый размер, а sockaddr_in добавлен с помощью sin_zero, чтобы сделать его того же размера. Я хотел бы знать, как компилятор знает, где получить информацию из sockaddr_in, если она отличается от sockaddr.

Ответы

Ответ 1

Это возможно, потому что вы обычно бросаете указатели, а не сами структуры. Вы делаете то, что на естественном языке означает "пожалуйста, обработайте этот указатель на socket structure как указатель на internet socket structure вместо этого". У компилятора нет проблем с повторной интерпретацией указателя.

Вот более подробное описание, взятое из комментариев:

A sockaddr имеет размер 16 байт - первые два байта - это sa_family, а остальные 14 байтов - это sa_data, которые являются произвольными данными. A sockaddr_in также имеет размер 16 байтов - первые 2 байта - это sin_family (всегда AF_INET), следующие 2 байта - sin_port, следующие 4 байта - это sin_addr (IP-адрес), а последние 8 байтов - это sin_zero, который не используется в IPv4 и предоставляется только для обеспечения 16 байтов. Таким образом, вы можете сначала взглянуть на sockaddr.sa_family, а если это AF_INET, то интерпретировать весь sockaddr как sockaddr_in.

A sockaddr_in не сохраняется внутри поля sockaddr.sa_data. Весь sockaddr - это весь sockaddr_in (когда sockaddr.sa_family есть AF_INET, то есть). Если вы берете указатель sockaddr* и набрасываете его на указатель sockaddr_in*, то:

  • sockaddr.sa_family sockaddr_in.sin_family
  • байты 0-1 из sockaddr.sa_data являются sockaddr_in.sin_port
  • байты 2-5: sockaddr_in.sin_addr
  • байты 6-13 являются sockaddr_in.sin_zero.