Why can we cast sockaddr to sockaddr_in

2020-06-08 16:55发布

问题:

I can see why it is useful to cast sockaddr to sockaddr_in, but I don't understand how this is possible. From what I've read, they're the same size and sockaddr_in is added with sin_zero to make it the same size. I would like to know how the compiler knows where to get the information from sockaddr_in if it is layed out differently to sockaddr.

回答1:

It is possible because you normally cast pointers, not the structures themselves. You do what in natural language means "please treat this pointer to a socket structure as a pointer to an internet socket structure instead". Compiler has no problems to re-interpret the pointer.

Here is more detailed description taken up from comments:

A sockaddr is 16 bytes in size - the first two bytes are the sa_family, and the remaining 14 bytes are the sa_data which is arbitrary data. A sockaddr_in is also 16 bytes in size - the first 2 bytes are the sin_family (always AF_INET), the next 2 bytes are the sin_port, the next 4 bytes are the sin_addr (IP address), and the last 8 bytes are the sin_zero which is unused in IPv4 and provided only to ensure 16 bytes. This way, you can look at sockaddr.sa_family first, and if it is AF_INET then interpret the entire sockaddr as a sockaddr_in.

A sockaddr_in is not stored inside of sockaddr.sa_data field. The entire sockaddr is the entire sockaddr_in (when sockaddr.sa_family is AF_INET, that is). If you take a sockaddr* pointer and cast it to a sockaddr_in* pointer, then:

  • sockaddr.sa_family is sockaddr_in.sin_family
  • bytes 0-1 of sockaddr.sa_data are sockaddr_in.sin_port
  • bytes 2-5 are sockaddr_in.sin_addr
  • bytes 6-13 are sockaddr_in.sin_zero.