无需强制转换即可创建 sockaddr

Creating a sockaddr without casting

我想创建一个没有有趣转换的 sockaddr 结构,因为我有一个函数可以 return sockaddr 结构。但我真的不知道如何将数据从 sockaddr_in 重新打包到 sockaddr。我正在关注 this tutorial,它显示了这样完成的

struct sockaddr_in myaddr;
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(0);
bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr);

我有一个 return 常规 sockaddr

的功能
sockaddr CreateAddress(std::string ip, uint16_t port){
    sockaddr_in address = {0};
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(ip.c_str());
    address.sin_port = htons(port);

    // return as sockaddr instead..
    sockaddr addr = {0};
    addr.sa_len = sizeof(sockaddr);
    addr.sa_family = AF_INET;
    // how to fill in sockaddr.sa_data?
    // maybe like this?
    addr.sa_data[0] = (address.sin_port >> 8) & 0xFF;
    addr.sa_data[1] = (address.sin_port) & 0xFF;
    addr.sa_data[2] = (address.sin_addr.s_addr >> 24) & 0xFF;
    addr.sa_data[3] = (address.sin_addr.s_addr >> 16) & 0xFF;
    addr.sa_data[4] = (address.sin_addr.s_addr >> 8) & 0xFF;
    addr.sa_data[5] = (address.sin_addr.s_addr) & 0xFF;
    return addr;
}

套接字 API 函数被构建为将 struct sockaddr * 作为参数,因为它可以接受多种套接字地址类型,即 struct sockaddr_un 用于 UNIX 域套接字,struct sockaddr_in 用于 IPv4,struct sockaddr_in6 用于 IPv6 等。struct sockaddr 类型是套接字 API(用 C 编写)实现继承的方式。

因此,这些函数实际上并不期望 struct sockaddr * 参数实际指向该类型的结构。根据套接字类型,它会在内部将其转换为正确的类型。

这意味着您应该使用 struct sockaddr_in 而不是 struct sockaddr 并在您与套接字函数交互时将这些结构的地址转换为 struct sockaddr *。这是使用这些功能的预期方式。

您不能 return(或传递或以其他方式使用)sockaddr 结构的值; sockaddr 不是 representing/containing 数据的实际类型,而是 C 和 Unix 早期的误导遗留抽象,用于“基础 class”,实际套接字地址类型是“派生的”来自".

如果您正在编写 C++,尽管您最初将其标记为 C,但您的问题表明您应该使用自己的 class 来表示数据,该 class 公开一个 struct sockaddr * 以传递给套接字函数需要它,同时在内部使用适当的类型进行存储。但是,无论您使用的是 C 还是 C++,手动创建此类对象通常都是错误的。你应该只使用 getaddrinfo.