2011-08-01 73 views
4

常量INADDR_ANY是所謂的IPv4通配符地址。 通配符IP地址對於綁定多宿主主機上的域套接字的應用程序非常有用。如果多宿主的應用程序將套接字綁定到其主機的一個IP地址,則該套接字只能接收發送到該IP地址的UDP數據報或TCP連接請求 。然而,我們通常需要一個 多宿主主機上的應用程序能夠接收數據報或連接請求 指定任何主機的IP地址,和插座結合 通配符IP地址,使之成爲可能。問題有關INADDR_ANY

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。 如果套接字可以在互聯網上接收到任何請求,它就可以很好地工作,我只是覺得在這裏b/c感到困惑。在互聯網上有大量的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 

回答

11

它沒有得到對每個IP地址的請求的互聯網上(一),它會爲每個IP地址,它的服務請求。例如,它可能有多個NIC,每個NIC都有一個單獨的IP地址,或者它可能有一個能夠管理多個IP地址的NIC(它甚至可能具有多個NIC,每個NIC都能夠處理多個IP地址)

The key段來看看是:

...我們通常要多宿主主機上的應用程序能夠接收指定任何主機的IP數據報的或連接請求解決(我的斜體字)。

換句話說,你可能有一個多機種設置您的機器服務10.0.0.1510.0.0.16。使用INADDR_ANY將允許你拿起流量這兩個地址,沒有拿起了10.0.0.17請求可能是機器在板凳上(或地球的另一側)的另一端。

下表,用最上面一行是請求目的地和左列是您正在收聽的地址,顯示您是否會得到一個請求(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 

(一),它甚至沒有看到絕大多數在網上請求。絕大多數甚至沒有把它送到離你最近的路由器(甚至可能是你的ISP)。即使那些使它到您最近的路由器,您的特定機器可能不會看到它們是否註定要在本地網段上的另一臺機器(儘管有混雜模式)。

+1

@ q0987除非請求某種診斷模式(即「數據包嗅探」),否則操作系統的網絡堆棧將不會將不是用於該機器地址之一的IP通信傳送給程序。通常,在較低級別和/或交換網絡中適當的分組尋址將防止大部分錯誤地址流量甚至高達網絡堆棧的IP級別。 –

+0

請參閱更新的客戶端代碼。客戶端代碼不指定服務器IP地址,在你的情況下,它沒有指定從10.0.0.15到10.0.0.16範圍內的任何IP地址。那麼服務器如何知道客戶端向它發送請求? – q0987

+0

@ q0987它可以幫助您瞭解網絡堆棧。每臺聯網的計算機都可以有一個或多個IP地址。它只會響應針對其中一個IP地址的流量。神奇地址0.0.0.0只是意味着「本機負責的任何IP地址」。 –