socket servidor library cliente c++ c api network-programming

c++ - servidor - ¿Cuál es la diferencia entre sockaddr, sockaddr_in y sockaddr_in6?



socket stream c (2)

Sé que sockaddr_in es para IPv4 y sockaddr_in6 para IPv6. La confusión para mí es la diferencia entre sockaddr y sockaddr_in [6].

Algunas funciones aceptan sockaddr y algunas funciones aceptan sockaddr_in o sockaddr_in6 , así que:

  • ¿cual es la regla?
  • ¿Y por qué hay una necesidad de dos estructuras diferentes?

Y porque el sizeof(sockaddr_in6) > sizeof(sockaddr) == sizeof(sockaddr_in) .

  • ¿Eso significa que siempre debemos usar sockaddr_in6 para asignar memoria en la pila y convertirla en sockaddr y sockaddr_in si necesitamos soportar ipv4 e ipv6?

Un ejemplo es: tenemos un socket y queremos obtener la dirección IP de la cadena (puede ser ipv4 o ipv6).

Primero llamamos a getsockname para obtener un addr y luego llamamos a inet_ntop función de addr.sa_family .

¿Hay algún problema con este fragmento de código?

sockaddr_in6 addr_inv6; sockaddr* addr = (sockaddr*)&addr_inv6; sockaddr_in* addr_in = (sockaddr_in*)&addr_inv6; socklen_t len = sizeof(addr_inv6); getsockname(_socket, addr, &len); char ipStr[256]; if (addr->sa_family == AF_INET6) { inet_ntop(addr_inv6.sin6_family, &addr_inv6.sin6_addr, ipStr, sizeof(ipStr)); // <<<<<<<<IS THIS LINE VALID, getsockname expected a sockaddr, but we use it output parameter as sockaddr_in6. } else { inet_ntop(addr_in->sin_family, &addr_in->sin_addr, ipStr, sizeof(ipStr)); }


No quiero responder mi pregunta Pero para dar más información aquí que podría ser útil para otras personas, decido responder mi pregunta.

Después de profundizar en el código fuente de linux . Lo que sigue es mi descubrimiento, hay un posible protocolo múltiple que implementa el nombre getsockname . Y cada uno tiene una estructura de datos de dirección subyacente, por ejemplo, para IPv4 es sockaddr_in , e IPV6 sockaddr_in6 , y AF_UNIX para el socket AF_UNIX . sockaddr se utilizan como el puntero de datos común en la firma de esas API.

Esas API copiarán socketaddr_in o sockaddr_in6 o sockaddr_un a sockaddr base en otra length parámetro mediante memcpy.

Y toda la estructura de datos comienza con el mismo tipo de campo sa_family.

En base a esos motivos, el fragmento de código es válido, porque sa_family y sa_family tienen sa_family y luego podemos convertirlo a la estructura de datos correcta para su uso después de comprobar sa_family .

BTY, no estoy seguro de por qué el tamaño de sizeof(sockaddr_in6) > sizeof(sockaddr) , que causa asignar memoria en el tamaño de sockaddr no es suficiente para ipv6 (que es propenso a errores), pero supongo que es por razones de historial .


sockaddr_in y sockaddr_in6 son estructuras donde el primer miembro es una estructura de sockaddr .

De acuerdo con el estándar C, la dirección de una estructura y su primer miembro son iguales, por lo que puede convertir el puntero a sockaddr_in(6) en un puntero a sockaddr .

Las funciones que toman sockaddr_in(6) como parámetro pueden modificar la parte sockaddr , y las funciones que toman sockaddr como parámetro solo se preocupan por esa parte.

Es un poco como herencia.