将IPv4/IPv6地址和端口设置为sockaddr_storage结构

Fat*_*lan 8 c++ sockets ip-address ipv6

我正在将IPv4应用程序移植到与AF无关的代码库(它应该与IPv4和IPv6一起使用).现在我在任何地方都使用sockaddr_storage,但是现在我必须设置(填充)一个sockaddr_storage.但我不知道正确的方法是什么.以前的代码是:

// defined in data_socket.h
struct sockaddr_in laddr;
Run Code Online (Sandbox Code Playgroud)

现在有这个函数设置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");
}
Run Code Online (Sandbox Code Playgroud)

如您所见,这是旧样式(使用IPv4).

现在我的变化如下.首先我改变sockaddr_insockaddr_storage

// defined in data_socket.h
struct sockaddr_storage laddr;
Run Code Online (Sandbox Code Playgroud)

然后我更改了上面的代码以支持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;

}
Run Code Online (Sandbox Code Playgroud)

}

在哪里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;
}
Run Code Online (Sandbox Code Playgroud)

我的方式似乎很复杂.这是正确的方法吗?因为我已经将sockaddr_in更改为sockaddr_storage,实际上我只想要反过来这个问题:从sockaddr结构中获取IPV4地址

我试图找到最佳的解决方案,例如在这里:http://www.kame.net/newsletter/19980604/它说,从来没有使用inet_ntop()inet_pton(),但其他一些人(如Beej的网络教程)说,inet_ntop()inet_pton()应使用用于基于IPv6的应用程序

我的实施方式是正确的还是我应该改变它?

Has*_*kun 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);
}
Run Code Online (Sandbox Code Playgroud)

  • `res->ai_addr` 指向 `struct sockaddr` 的一些变体,可以是 `sockaddr_in` 或 `sockaddr_in6`。没有进行任何转换,结构只是按原样复制。`struct sockaddr_storage` 的大小和布局允许它被转换成任何 `sockaddr` 变体,所有这些变体共享一个公共头。回复:传递一个字符串作为端口,我不会打扰,但这是你的代码。(另外,修复了拼写错误,getaddrinfo 本来是缓冲区) (2认同)