linux - sockaddr_in - inaddr_any que es
Pregunta sobre INADDR_ANY (1)
La constante INADDR_ANY es la llamada dirección de comodín IPv4. La dirección IP comodín es útil para aplicaciones que enlazan sockets de dominio de Internet en hosts con hosts múltiples. Si una aplicación en un host con múltiples hosts vincula un socket a solo una de las direcciones IP del host, entonces ese socket solo puede recibir datagramas UDP o solicitudes de conexión TCP enviadas a esa dirección IP. Sin embargo, normalmente queremos que una aplicación en un host de múltiples hosts pueda recibir datagramas o solicitudes de conexión que especifiquen alguna de las direcciones IP del host, y vincular el socket a la dirección IP comodín lo hace posible.
struct sockaddr_in server_address;
int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&server_address, 0, sizeof(struct sockaddr_in));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY); // here is my quesion
server_address.sin_port = htons(9734);
bind(server_sockfd, (struct sockaddr*)&server_address, sizeof(server_address));
Pregunta>
Si vinculamos el socket a una dirección IP específica, entonces el socket solo puede recibir solicitudes UPD / TCP enviadas a esa dirección IP.
Como muestro en el código anterior, ahora el socket server_sockfd está vinculado con INADDR_ANY. Me siento confundido aquí b / c si el socket puede recibir cualquier solicitud en Internet, cómo puede funcionar bien. Hay toneladas de solicitudes de UDP / TCP en Internet, si las respuestas de socket a todo el mundo, ¿cómo puede funcionar?
// código actualizado para el lado del cliente //
int
main(int argc, char *argv[])
{
struct sockaddr_in6 svaddr;
int sfd, j;
size_t msgLen;
ssize_t numBytes;
char resp[BUF_SIZE];
if (argc < 3 || strcmp(argv[1], "--help") == 0)
usageErr("%s host-address msg.../n", argv[0]);
/* Create a datagram socket; send to an address in the IPv6 somain */
sfd = socket(AF_INET6, SOCK_DGRAM, 0); /* Create client socket */
if (sfd == -1)
errExit("socket");
memset(&svaddr, 0, sizeof(struct sockaddr_in6));
svaddr.sin6_family = AF_INET6;
svaddr.sin6_port = htons(PORT_NUM);
if (inet_pton(AF_INET6, argv[1], &svaddr.sin6_addr) <= 0)
fatal("inet_pton failed for address ''%s''", argv[1]);
/* Send messages to server; echo responses on stdout */
for (j = 2; j < argc; j++) {
msgLen = strlen(argv[j]);
if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
sizeof(struct sockaddr_in6)) != msgLen)
fatal("sendto");
numBytes = recvfrom(sfd, resp, BUF_SIZE, 0, NULL, NULL);
if (numBytes == -1)
errExit("recvfrom");
printf("Response %d: %.*s/n", j - 1, (int) numBytes, resp);
}
exit(EXIT_SUCCESS);
}
// actualizado para el código del lado del servidor
int
main(int argc, char *argv[])
{
struct sockaddr_in6 svaddr, claddr;
int sfd, j;
ssize_t numBytes;
socklen_t len;
char buf[BUF_SIZE];
char claddrStr[INET6_ADDRSTRLEN];
/* Create a datagram socket bound to an address in the IPv6 somain */
sfd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sfd == -1)
errExit("socket");
memset(&svaddr, 0, sizeof(struct sockaddr_in6));
svaddr.sin6_family = AF_INET6;
svaddr.sin6_addr = in6addr_any; /* Wildcard address */
svaddr.sin6_port = htons(PORT_NUM);
if (bind(sfd, (struct sockaddr *) &svaddr,
sizeof(struct sockaddr_in6)) == -1)
errExit("bind");
/* Receive messages, convert to uppercase, and return to client */
for (;;) {
len = sizeof(struct sockaddr_in6);
numBytes = recvfrom(sfd, buf, BUF_SIZE, 0,
(struct sockaddr *) &claddr, &len);
if (numBytes == -1)
errExit("recvfrom");
/* Display address of client that sent the message */
if (inet_ntop(AF_INET6, &claddr.sin6_addr, claddrStr,
INET6_ADDRSTRLEN) == NULL)
printf("Couldn''t convert client address to string/n");
else
printf("Server received %ld bytes from (%s, %u)/n",
(long) numBytes, claddrStr, ntohs(claddr.sin6_port));
for (j = 0; j < numBytes; j++)
buf[j] = toupper((unsigned char) buf[j]);
if (sendto(sfd, buf, numBytes, 0, (struct sockaddr *) &claddr, len) !=
numBytes)
fatal("sendto");
}
}
// actualizado para saber cómo ejecutar este servidor / programas de cliente.
$ ./server_program &
[1] 31047
$ ./client_program ::1 ciao // Send to server on local host
Server received 4 bytes from (::1, 32770)
Response 1: CIAO
No recibe solicitudes para cada dirección IP en Internet (a) , recibe solicitudes para cada dirección IP que brinda. Por ejemplo, puede tener varias NIC, cada una con una dirección IP separada o puede tener una única NIC capaz de administrar múltiples direcciones IP (incluso puede tener varias NIC, cada una capaz de manejar múltiples direcciones IP).
El fragmento de clave para mirar es:
... normalmente queremos una aplicación en un host multi-hogar para poder recibir datagramas o solicitudes de conexión que especifiquen alguna de las direcciones IP del host (mis cursivas).
En otras palabras, puede tener una configuración multitarjeta en la que su máquina 10.0.0.15
servicios 10.0.0.15
y 10.0.0.16
. El uso de INADDR_ANY
le permitirá recoger el tráfico de ambas direcciones, sin recoger las solicitudes de 10.0.0.17
que pueden ser la máquina en el otro extremo del banco (u otro lado del planeta).
La siguiente tabla, donde la fila superior es destinos de solicitud y la columna izquierda es la dirección en la que está escuchando, muestra si recibirá una solicitud ( Y
) o no ( N
):
Request to> 10.0.0.15 10.0.0.16 10.0.0.17
Bind to: *-------------------------------
10.0.0.15 | Y N N
10.0.0.16 | N Y N
INADDR_ANY | Y Y N
(a) Ni siquiera ve la gran mayoría de las solicitudes en la red. La gran mayoría ni siquiera llega al enrutador más cercano (o probablemente incluso a su ISP). Incluso aquellos que llegan al enrutador más cercano, su máquina particular podría no ver si están destinados a otra máquina en el segmento local (a pesar del modo promiscuo).