我正在将 IPv4 应用程序移植到 AF-independent 代码库(它应该与IPv4和IPv6一起使用)。现在我正在使用 sockaddr_storage ,但是现在我必须设置(填充) sockaddr_storage 。但我不知道正确的方法是什么。之前的代码是:
// defined in data_socket.h
struct sockaddr_in laddr;
现在有这个功能设置 sin_addr 和 sin_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;
然后我更改了上面的代码以支持 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更改为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 的应用。
我的实施方式是正确还是应该更改?
答案 0 :(得分: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);
}
答案 1 :(得分: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风格的演员阵容很不明确。