2012-02-21 36 views
3

我有一個問題,我創建兩個UDP套接字,將它們綁定到端口0的環回地址(請求堆棧分配一個臨時端口)。我的理解是,兩個套接字應該位於不同的端口上。在下面的代碼示例中,兩個套接字都報告在同一個IP地址和端口上。爲什麼綁定返回相同的臨時端口?

#include <stdio.h> 
#include <arpa/inet.h> 

int main(int, char**) 
{ 
    int fd1 = ::socket(AF_INET, SOCK_DGRAM, 0); 
    if (fd1 < 0) 
    { 
     perror("fd1 socket()"); 
     return -1; 
    } 
    int fd2 = ::socket(AF_INET, SOCK_DGRAM, 0); 
    if (fd2 < 0) 
    { 
     perror("fd2 socket()"); 
     return -1; 
    } 

    // Set SO_REUSEADDR for both sockets 
    int reuse = 1; 
    if (::setsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) 
    { 
     perror("fd1 SO_REUSEADDR failed"); 
     return -1; 
    } 
    if (::setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) 
    { 
     perror("fd2 SO_REUSEADDR failed"); 
     return -1; 
    } 

    sockaddr_storage storage; 
    socklen_t addrlen = sizeof(storage); 
    sockaddr_in& addr = reinterpret_cast<sockaddr_in&>(storage); 
    addr.sin_family = AF_INET; 
    addr.sin_port = 1234; 
    addr.sin_port = 0; 
    if (::inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) <= 0) 
    { 
     perror("Failed to create address 127.0.0.1"); 
     return -1; 
    } 
    sockaddr* pAddr = reinterpret_cast<sockaddr*>(&storage); 

    if (::bind(fd1, pAddr, addrlen) < 0) 
    { 
     perror("bind fd1 failed"); 
     return -1; 
    } 

    // Get the local address for fd1 
    addrlen = sizeof(storage); 
    if (::getsockname(fd1, pAddr, &addrlen)) 
    { 
     perror("getsockname for fd1 failed"); 
     return -1; 
    } 
    char straddr[INET_ADDRSTRLEN]; 
    if (!inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr))) 
    { 
     perror("inet_ntop for fd1 failed"); 
     return -1; 
    } 
    printf("fd1=%d addr=%s:%d\n", fd1, straddr, addr.sin_port); 

    if (::bind(fd2, pAddr, addrlen) < 0) 
    { 
     perror("bind fd2 failed"); 
     return -1; 
    } 

    // Get the local address for fd2 
    addrlen = sizeof(storage); 
    if (::getsockname(fd2, pAddr, &addrlen)) 
    { 
     perror("getsockname for fd2 failed"); 
     return -1; 
    } 
    if (!inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr))) 
    { 
     perror("inet_ntop for fd2 failed"); 
     return -1; 
    } 
    printf("fd2=%d addr=%s:%d\n", fd2, straddr, addr.sin_port); 

    return 0; 
} 

該代碼給出了下面的輸出...

fd1=4 addr=127.0.0.1:1933 
fd2=5 addr=127.0.0.1:1933 

我需要在同一(本地)IP地址都插座,但不同的端口。任何人都可以解釋爲什麼兩個套接字共享相同的端口?任何人都可以提出修正?

回答

2

這是UDP套接字上SO_REUSEADDR的預期行爲。刪除該設置以返回到正常分配規則。

+0

這不是SO_REUSEADDR選項。刪除它意味着第二個綁定失敗。您應該能夠將兩個UDP套接字綁定到相同的接口並具有不同的端口。 – Drew 2012-02-21 21:43:07

+0

我還應該提到,如果我將fd2的綁定移動到fd1的綁定下方,我會得到不同的端口。很奇怪。我無法解釋這種行爲。 – Drew 2012-02-21 21:44:52

+2

這是因爲綁定fd1後,您可以使用'paddr'調用'getsockname()'。所以你的第二個綁定請求分配給fd1的同一個端口號。設置'SO_REUSEADDR'會導致它允許,即使這不是你想要的。確保在第二次綁定之前重置「paddr」。 – 2012-02-21 22:36:13

相關問題