为什么必须在此代码中强制转换为struct in_addr?

时间:2017-12-11 08:36:06

标签: c++ sockets tcp-ip

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'这段代码意味着什么?

2 个答案:

答案 0 :(得分:4)

你不需要演员转换为void*,这就是第二个论点。

但是,您在该代码中遇到了一些其他问题。

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

另一个问题是(不必要的)施放你。如果您遵循这些结构,sockaddr_in结构将在<netinet/in.h>头文件中定义。成员sin_addr的类型为in_addrin_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缓冲区大小来说有点过分。 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);    
}