将sockaddr中的IP地址转换为uint32_t

4
我正在尝试将存储在struct sockaddr中的IP地址(v4)转换为uint32_t
//struct sockaddr in_addr;
struct sockaddr_in* addr = (struct sockaddr_in*)&in_addr;

uint32_t clientIpAddr = static_cast<uint32_t>(addr->sin_addr.s_addr);
uint16_t clientPortNumber = addr->sin_port;

首先,我想知道这是否会起作用。

其次,将IP地址转换为char[4]并稍后将其转换为uint32_t是否更好?

第三,IP地址0.0.0.1会被转换为数字1吗?还是因为字节顺序而变成其他东西?


1
你不应该一开始就将变量声明为 sockaddr。应该声明为 sockaddr_in(IPv4)、sockaddr_in6(IPv6)或 sockaddr_storage(IP-不可知),然后在将它们传递给各种套接字函数(connect()accept()等)时,将它们强制转换为 sockaddr*。无论如何,要从 in_addr 中提取 IPv4 地址,请确保 in_addr.sa_familyAF_INET,然后对 sockaddr_in 进行类型转换即可(您不需要对 s_addr 值进行 static_cast,但如果您要使用 C++ 强制转换,则应对 in_addr 转换使用 reinterpret_cast)。 - Remy Lebeau
@RemyLebeau 非常感谢! :) - Eddie
2个回答

9

可以,它能够正常工作。

根据文档struct in_addr定义如下:

struct in_addr {
    uint32_t s_addr; /* address in network byte order */
};

所以,是的,你可以将它分配给一个uint32_t(甚至不需要强制转换)。

"网络字节顺序"确实也告诉我们,如果你在一个不是大端的机器上运行它,你最终会得到垃圾值。你需要通过ntohl()来修复它。


3

只要你不试图打印clientIpAddr, 而是在对sendto或bind的调用中重复使用它,这个转换就可以正常工作。

为了正确地转换地址,您需要使用ntohl函数,该函数将从网络字节顺序转换为主机字节顺序,否则0.0.0.1地址的值将为clientIpAddr中的0x1000000:

uint32_t clientIpAddr = ntohl(addr->sin_addr.s_addr);

吹毛求疵:只有在小端机器上才会看起来像那样。在大端机器上,网络顺序和主机顺序是相同的。曾经也有“中间”字节序的机器,它们很奇怪 :-) - Wouter Verhelst
2
通常情况下,您不需要将IP地址从网络字节顺序转换为主机字节顺序,因为套接字API在IPv4地址上使用网络字节顺序。如果您想要IP地址的人类可读表示,请使用inet_ntoa()inet_ntop()或相应的函数。相反,您更经常需要使用主机字节顺序的端口号:uint16_t clientPortNumber = ntohs(addr->sin_port); - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接