9

IPv4アプリケーションをAF に依存しないコードベースに移植しています (IPv4 および IPv6 で動作するはずです)。今、私はできる限りsockaddr_storageを使用していますが、今は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_inたのはsockaddr_storage

// defined in data_socket.h
struct sockaddr_storage laddr;

次に、 IPv4IPv6をサポートするように上記のコードを変更しました。

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 を sockaddr_storage に変更したため、実際には、この質問の逆をしたいだけです: sockaddr 構造から IPV4 アドレスを取得する

たとえば、ここで最善の解決策を見つけようとしています: http://www.kame.net/newsletter/19980604/それは決して使用inet_ntop()しないと言っていますinet_pton()が、他のいくつか(Beejのネットワークチュートリアルなど)はそれを言ってinet_ntop()おり、inet_pton()使用する必要がありますIPv6ベースのアプリケーション向け。

私の実装方法は正しいですか、それとも変更する必要がありますか?

4

2 に答える 2

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);
}
于 2012-07-12T14:43:19.197 に答える
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 スタイルのキャストは、あいまいではありません。

于 2012-07-12T14:41:55.830 に答える