【问题标题】:Why does it have to cast to struct in_addr in this code?为什么必须在这段代码中强制转换为 struct in_addr?
【发布时间】:2018-05-24 17:51:43
【问题描述】:
TCPStream::TCPStream(int sd, struct sockaddr_in* address) : msd(sd) 
{
    char ip[50];
    inet_ntop(PF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, sizeof(ip)-1);
    m_peerIP = ip;
    m_peerPort = ntohs(address->sin_port);
}

为什么必须在这段代码中强制转换为struct in_addr

这段代码中的“50”是什么意思?

【问题讨论】:

  • 要学习一门编程语言,有人应该遵循从初学者到更高级别的教程。
  • “'50' 在这段代码中是什么意思?” - 在日常生活中的意思是一样的。有多少东西。
  • 为什么一定要50,49呢?
  • "cast to "struct in_addr" 代码转换为指向struct in_addr的*指针,即struct in_addr *

标签: c++ sockets tcp-ip


【解决方案1】:

您不需要强制转换即可转换为 void*,这是第二个参数。

但是,您在使用该代码时确实存在一些其他问题。

让我们从inet_ntop 调用的第一个参数开始:您使用PF_INET。前缀 PF 代表 Protocol 系列。由于您正在获取有关地址的信息,因此您应该改用 AF_INET 符号常量,其中 AF 代表地址家庭。

另一个问题是你做的(不必要的)演员。如果遵循结构,sockaddr_in 结构在<netinet/in.h> 头文件中定义。成员sin_addr 的类型为in_addr。而in_addr 有一个成员s_addr,其类型为in_addr_t(相当于uint32_t)。也就是说,&(address->sin_addr.s_addr) 是一个指向无符号 32 位整数类型的指针。不是struct in_addr*(应该是&address->sin_addr)。

如果我们把所有这些放在一起,正确的调用应该是

inet_ntop(AF_INET, &address->sin_addr.s_addr, ip, sizeof ip);

现在关于数组的大小50。这有点大,因为 IPv4 地址最多可以有 16 个字符(包括字符串终止符)。这也恰好是宏 INET_ADDRSTRLEN 的值。

所以数组可以定义为

char ip[INET_ADDRSTRLEN];

【讨论】:

  • 正确的调用应该是inet_ntop(AF_INET, &(address->sin_addr), ip, sizeof ip);。将& 运算符应用于sin_addr 成员,而不是s_addr 成员(在这种情况下,它恰好sin_addr 位于同一地址,但这样做并不好依靠这个)。 inet_ntop() 需要 in_addr*,所以给它一个指向实际 in_addr 的指针
  • @RemyLebeau Weird,the POSIX reference 没有提及struct in_addr,只是“[t]he src 参数指向一个保存 IPv4 地址的缓冲区,如果af 参数是 AF_INET"
  • LinuxWindows inet_ntop() 的文档特别声明 in_addr 是必需的
【解决方案2】:

address->sin_addr 字段是一个in_addr 结构,它有一个数据字段s_addr,即uint32_t。因此,s_addr 字段的地址恰好与其包含in_addr 的地址相同。虽然在这种情况下这种类型的转换是“安全的”,但它也是错误的

根据inet_ntop() 的 Linux 文档:

AF_INET `src` 指向一个 `struct in_addr` (按网络字节顺序) 以点分十进制形式转换为 IPv4 网络地址 格式,`"ddd.ddd.ddd.ddd"`。缓冲区 `dst` 必须至少为 `INET_ADDRSTRLEN` 字节长。

如您所见,inet_ntop() 需要一个用于 IPv4 地址的 in_addr* 指针。 address->sin_addr 字段是一个实际的in_addr,因此您应该将address->sin_addr 的地址传递给inet_ntop(),而不是address->sin_addr.s_addr 的地址。

一个 IPv4 地址最多只占用 15 个字符,外加一个空终止符。所以50 对你的ip 缓冲区大小来说太过分了。 16INET_ADDRSTRLEN 的定义是)就足够了。

正确的代码应该更像这样:

TCPStream::TCPStream(int sd, struct sockaddr_in* address) : msd(sd) 
{
    char ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &(address->sin_addr), ip, sizeof(ip));
    m_peerIP = ip;
    m_peerPort = ntohs(address->sin_port);    
}

【讨论】:

    猜你喜欢
    • 2020-06-04
    • 1970-01-01
    • 2023-03-17
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多