2012-07-12 92 views
7

我移植一個的IPv4應用到AF-獨立代碼庫(它應該與IPv4和IPv6工作)。現在我正在使用sockaddr_storage只要我可以,但現在我必須設置(填充)sockaddr_storage。但我不知道正確的方法是什麼。上面的代碼是:設置的IPv4/IPv6地址和端口一個struct sockaddr_storage的結構

// defined in data_socket.h 
struct sockaddr_in laddr; 

現在有這個功能,設置sin_addrsin_port

void DataSocket::SetLocalAddr(const char *addr, const int port) 
{ 
    this->laddr.sin_port = htons(port); 
    if(addr != NULL) 
     this->laddr.sin_addr.s_addr = inet_addr(addr); 
    else 
     this->laddr.sin_addr.s_addr = inet_addr("0.0.0.0"); 
} 

正如你看到的,這是舊的樣式(使用IPv4)。

現在我的更改如下。首先,我已經改變了sockaddr_insockaddr_storage

// defined in data_socket.h 
struct sockaddr_storage laddr; 

然後,我改變了上面的代碼以支持IPv4的 IPv6的

void DataSocket::SetLocalAddr(const char *addr, const int port) 
{ 
switch (this->GetAddrFamily(addr)) { 
    case AF_INET: 
     (struct sockaddr_in *) this->laddr.sin_port = htons(port); 
     if(addr != NULL) 
      inet_pton(AF_INET, addr, (struct sockaddr_in *) this->laddr.sin_addr); 
     else 
      inet_pton(AF_INET, "0.0.0.0", (struct sockaddr_in *) this->laddr.sin_addr); 
     break; 

    case AF_INET6: 
     (struct sockaddr_in6 *) this->laddr.sin6_port = htons(port); 
     if(addr != NULL) 
      inet_pton(AF_INET6, addr, (struct sockaddr_in6 *) this->laddr.sin6_addr); 
     else 
      inet_pton(AF_INET6, "0:0:0:0:0:0:0:0", (struct sockaddr_in6 *) this->laddr.sin6_addr); 
     break; 

    default: 
     return NULL; 

} 

}

哪裏GetAddrFamily()是:

int DataSocket::GetAddrFamily(const char *addr) 
{ 
    struct addrinfo hints, *res; 
    int status, result; 

    memset(&hints, 0, sizeof(hints)); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 

    if ((status = getaddrinfo(addr, 0, &hints, &res)) != 0) 
    { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); 
     return false; 
    } 

    result = res->ai_family; // This might be AF_INET, AF_INET6,etc.. 
    freeaddrinfo(res); // We're done with res, free it up 

    return result; 
} 

看來我的方法很複雜。這是做到這一點的正確方法嗎?因爲我已經改變了SOCKADDR_IN到struct sockaddr_storage的,其實我只是想這個問題的反面:Getting IPV4 address from a sockaddr structure

我試圖找到最佳的解決方案,例如在這裏:http://www.kame.net/newsletter/19980604/它說,從來沒有使用inet_ntop()inet_pton(),但有些人(比如Beej的網絡教程)說inet_ntop()inet_pton()應該用於IPv6的應用程序。

我的執行方式是否正確或應該更改?

+1

這就是爲什麼我喜歡'boost :: asio :: ip :: address',它將'boost :: asio :: ip :: address_v4'和'boost :: asio :: ip :: address_v6'。 – Chad 2012-07-12 14:00:16

+1

當C獲得成員函數時讓我知道。 – Puppy 2012-07-12 15:59:35

+0

@DeadMG哎呀抱歉'''標籤 – 2012-07-12 16:04:32

回答

5

我強烈建議讓getaddrinfo做所有繁重的工作,例如。

void DataSocket::SetLocalAddr(const char *addr, const unsigned short int port) 
{ 
    struct addrinfo hints, *res; 
    int status; 
    char port_buffer[6]; 

    sprintf(port_buffer, "%hu", port); 

    memset(&hints, 0, sizeof(hints)); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    /* Setting AI_PASSIVE will give you a wildcard address if addr is NULL */ 
    hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE; 

    if ((status = getaddrinfo(addr, port_buffer, &hints, &res) != 0) 
    { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); 
     return; 
    } 

    /* Note, we're taking the first valid address, there may be more than one */ 
    memcpy(&this->laddr, res->ai_addr, res->ai_addrlen); 

    freeaddrinfo(res); 
} 
+0

感謝您的代碼。但是我對'memcpy(&this-> laddr,res-> ai_addr,res-> ai_addrlen);'line'感到困惑。 'res-> ai_addr'是一個sockaddr結構,我猜它會自動轉換爲'sockaddr_in'或'sockaddr_in6'?它如何存儲到'this-> laddr'中(因爲'this-> laddr'是'sockaddr_storage'結構)? – 2012-07-12 15:11:44

+0

我想我應該在'getaddrinfo'中使用'port_buffer'而不是'port',因爲'getaddrinfo()'除了const char *(又名字符串)? – 2012-07-12 15:19:32

+1

'res-> ai_addr'指向'struct sockaddr'的一些變體,可以是'sockaddr_in'或'sockaddr_in6'。沒有轉換正在進行,結構只是被原樣複製。 'struct sockaddr_storage'的大小和佈局允許將其轉換爲任何'sockaddr'變體,所有這些變體都共享一個標頭。重新:傳遞一個字符串作爲端口,我不會打擾,但它是你的代碼。 (另外,固定錯字,getaddrinfo本來就是緩衝區) – Hasturkun 2012-07-12 15:56:20

1

如果我理解正確,您是將this轉換爲第一個成員?不要這樣做,請指定該成員。

我也將使它更容易通過引入{}範圍和雙方的情況下,局部變量,像閱讀:

{ 
struct sockaddr_in * in4 = reinterpret_cast< struct sockaddr_in * >(&this->addr); 
in4->laddr.sin_port = htons(port); 
... etc 
} 

的,因爲你正在使用C++而不是C表示,使用C++風格的轉換。用C++進行C風格的轉換遠不夠模糊。

相關問題