为什么必须在这段代码中强制转换为 struct in_addr ?
Why does it have to cast to struct in_addr in this code?
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”是什么意思?
您不需要转换为 void*
,这是第二个参数。
不过,您的代码确实存在一些其他问题。
让我们从 inet_ntop
调用的第一个参数开始:您使用 PF_INET
。前缀 PF
代表 Protocol Family。由于您正在获取有关地址的信息,因此您应该使用 AF_INET
符号常量,其中 AF
代表 Address Family.
另一个问题是你做的(不必要的)演员表。如果您遵循这些结构,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];
address->sin_addr
字段是一个 in_addr
结构,它有一个数据字段 s_addr
,即 uint32_t
。因此,s_addr
字段的地址 碰巧 与其包含的 in_addr
的地址相同。虽然在这种情况下这种转换是 "safe",但它也是 错误的。
根据 inet_ntop()
的 Linux 文档:
AF_INET
`src` points to a `struct in_addr` (in network byte order) which
is converted to an IPv4 network address in the dotted-decimal
format, `"ddd.ddd.ddd.ddd"`. The buffer `dst` must be at least
`INET_ADDRSTRLEN` bytes long.
如您所见,inet_ntop()
需要一个 in_addr*
指向 IPv4 地址的指针。 address->sin_addr
字段是实际的 in_addr
,因此您应该将 address->sin_addr
的地址传递给 inet_ntop()
,而不是 address->sin_addr.s_addr
.[=31= 的地址]
一个IPv4地址最多只需要15个字符,加上一个空终止符。所以 50
对你的 ip
缓冲区大小来说太过分了。 16
(INET_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);
}
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”是什么意思?
您不需要转换为 void*
,这是第二个参数。
不过,您的代码确实存在一些其他问题。
让我们从 inet_ntop
调用的第一个参数开始:您使用 PF_INET
。前缀 PF
代表 Protocol Family。由于您正在获取有关地址的信息,因此您应该使用 AF_INET
符号常量,其中 AF
代表 Address Family.
另一个问题是你做的(不必要的)演员表。如果您遵循这些结构,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];
address->sin_addr
字段是一个 in_addr
结构,它有一个数据字段 s_addr
,即 uint32_t
。因此,s_addr
字段的地址 碰巧 与其包含的 in_addr
的地址相同。虽然在这种情况下这种转换是 "safe",但它也是 错误的。
根据 inet_ntop()
的 Linux 文档:
AF_INET `src` points to a `struct in_addr` (in network byte order) which is converted to an IPv4 network address in the dotted-decimal format, `"ddd.ddd.ddd.ddd"`. The buffer `dst` must be at least `INET_ADDRSTRLEN` bytes long.
如您所见,inet_ntop()
需要一个 in_addr*
指向 IPv4 地址的指针。 address->sin_addr
字段是实际的 in_addr
,因此您应该将 address->sin_addr
的地址传递给 inet_ntop()
,而不是 address->sin_addr.s_addr
.[=31= 的地址]
一个IPv4地址最多只需要15个字符,加上一个空终止符。所以 50
对你的 ip
缓冲区大小来说太过分了。 16
(INET_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);
}