常量INADDR_ANY是所谓的IPv4通配符地址。通配符IP地址对于在多宿主主机上绑定Internet域套接字的应用程序很有用。如果多宿主主机上的应用程序将套接字仅绑定到其主机的IP地址之一,则该套接字只能接收发送到该IP地址的UDP数据报或TCP连接请求。但是,我们通常希望多宿主主机上的应用程序能够接收指定主机IP地址的数据报或连接请求,并将套接字绑定到通配符IP地址可以实现这一点。
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));
问题>
如果我们将套接字绑定到特定的IP地址,则套接字只能接收发送到该IP地址的UPD / TCP请求。
如我上面的代码所示,现在套接字server_sockfd与INADDR_ANY绑定。如果套接字可以在互联网上收到任何请求,我仍然感到困惑,因为它仍然可以正常工作。互联网上有大量的UDP / TCP请求,如果套接字对所有人都有响应,它又如何工作?
//更新了客户端代码//
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); }
//更新了服务器端代码
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"); } }
//更新了有关如何运行此服务器/客户端程序的信息。
$ ./server_program & [1] 31047 $ ./client_program ::1 ciao // Send to server on local host Server received 4 bytes from (::1, 32770) Response 1: CIAO
它不会获取对Internet (a)上每个IP地址的请求,而是会获取其服务的每个IP地址的请求。例如,它可能具有多个NIC,每个NIC都有一个单独的IP地址,或者它可能具有一个能够管理多个IP地址的NIC(它甚至可能具有多个NIC,每个NIC能够处理多个IP地址。
要查看的关键代码段是:
…我们通常希望多宿主主机上的应用程序能够接收指定 主机IP地址 (斜体)的数据报或连接请求。
换句话说,您可能有一个多宿主设置,其中您的机器服务10.0.0.15和10.0.0.16。使用,INADDR_ANY您可以选择这两个地址的流量, 而无需 选择10.0.0.17可能是工作台另一端(或地球另一侧)上的计算机的请求。
10.0.0.15
10.0.0.16
INADDR_ANY
10.0.0.17
下表中的第一行是请求的目的地,左列是您正在监听的地址,该表格显示了是否会向您发送请求Y(N):
Y
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)甚至在网络上都 看不到 绝大多数请求。绝大多数人甚至都没有将它连接到最近的路由器(甚至可能是您的ISP)。即使是那些 确实连接 到您最近的路由器的计算机,您的特定计算机也可能看不到它们是否是发往本地网段上的另一台计算机的(尽管是混杂模式)。