将sockaddr中的IP地址转换为in_addr

10

我需要将放置在结构 sockaddr 中的套接字地址转换为结构 in_addr 。 我试图理解这些结构中IP地址的存储方式:

struct sockaddr
{
    u_short sa_family;      /* address family */
    char    sa_data[14];    /* up to 14 bytes of direct address */
};


struct in_addr 
{
    union
    {
        struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
        struct { u_short s_w1,s_w2; } S_un_w;
        u_long S_addr;
    }
    S_un;
};

我被一个问题困住了,就是如何把127.0.0.1存储在sa_data的14个字符中。 将sockaddr转换为in_addr的最佳方法是什么?


这个问题讨论编码 - https://dev59.com/uHM_5IYBdhLWcg3wrFIt - sashoalm
1个回答

12
sockaddr是一个通用的结构体,被不同类型的套接字所共享。对于TCP/IP套接字,此结构体变成了sockaddr_in(IPv4)或sockaddr_in6(IPv6)。对于Unix套接字,它变成了sockaddr_un
理想情况下,应该使用sockaddr_in来代替sockaddr
但是如果给定了sockaddr,可以通过以下方式从中提取IP地址:
sockaddr foo;
in_addr ip_address = ((sockaddr_in)foo).sin_addr;
or
in_addr_t ip_address = ((sockaddr_in)foo).sin_addr.s_addr;

如果您查看sockaddr_in的内部,您会发现sa_data的前2个字节是端口号。接下来的4个字节是IP地址。

PS:请注意,IP地址以网络字节序存储,因此您可能需要使用ntohl(网络到主机)和htonl(主机到网络)进行转换。

更新

对于IPv6,情况类似:

sockaddr foo;
in_addr6 ip_address = ((sockaddr_in6)foo).sin6_addr;

要访问单个字节,请使用ip_address[0] ... ip_address[15]
sockaddr_in6结构体内,sa_data的前2个字节是端口号,下4个字节是流信息(flow info),其余16个字节是IPv6地址。
但需要注意的是,sockaddr_in6sockaddr更大,因此在从sockaddr转换为sockaddr_in6时,请检查地址族是否确实是IPv6地址,通过检查地址族foo.sa_family == AF_INET6

这就是我需要的。但是当我有IPV6时如何进行转换? - vico
@vico,我已经更新了答案。也许你应该更新一下问题,因为它没有提到IPv6。如果你对答案满意,请随意接受它。 - Super-intelligent Shade

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