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

标签 c++ sockets ip-address ipv6

我正在将一个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,实际上我只是想要这个问题的反面:Getting IPV4 address from a sockaddr structure

我正在努力寻找最佳解决方案,例如此处:http://www.kame.net/newsletter/19980604/它说永远不要使用 inet_ntop()inet_pton(),但是其他一些人(比如 Beej 的网络教程)说 inet_ntop()inet_pton() 应用于基于 IPv6 的应用程序。

我的实现方式是否正确,还是应该更改?

最佳答案

我强烈建议让 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);
}

关于c++ - 将 IPv4/IPv6 地址和端口设置为 sockaddr_storage 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11453390/

相关文章:

c++ - 从用四边形绘制的形状转换为用三角形绘制的形状

vb.net - 使用VB.net进行套接字编程和telnet

mysql - 添加通配符IP如192.168.1.%时远程Mysql数据库访问错误

python - 如何在 Python 2.x 中区分某个范围内的 IP 地址范围?

unique - 允许每台计算机一票(非IP,未登录用户)

c++ - 如何将 MATLAB 图像处理库内置函数转换为 matlab coder 代码生成不支持的 c++?

c++ - 标准流适配器

c++ - 在 visual studio 2015 community c++ 中,如何修复警告 C4838 : conversion from 'unsigned int' to 'int' requires a narrowing conversion

sql - ODBC在执行SQLFreeHandle之后何时关闭连接?

java - 如何检查主机是否可达?