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'这段代码意味着什么?
答案 0 :(得分:4)
你不需要演员转换为void*
,这就是第二个论点。
但是,您在该代码中遇到了一些其他问题。
让我们从inet_ntop
调用的第一个参数开始:您使用PF_INET
。前缀PF
代表 协议 系列。由于您获得了有关地址的信息,因此您应该使用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];
答案 1 :(得分:1)
address->sin_addr
字段是in_addr
结构,其中包含s_addr
的单个数据字段uint32_t
。因此,s_addr
字段的地址与其包含in_addr
的地址相同。虽然这种铸件是安全的#34;在这种情况下,它也是错误的。
根据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
的地址。
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);
}