将IP地址从sockaddr转换为in_addr

vic*_*ico 3 c++ sockets visual-c++

我需要将结构中放置的套接字地址转换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;
Run Code Online (Sandbox Code Playgroud)

我被问到如何127.0.0.1存储在14个字符中的问题sa_data.将sockaddr转换为in_addr的最佳方法是什么?

Inn*_*der 5

sockaddr是一个通用的结构,由不同类型的套接字共享.对于TCP/IP套接字,此结构变为sockaddr_in.对于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;
Run Code Online (Sandbox Code Playgroud)

如果您查看内部,sockaddr_in您将看到前2个字节sa_data是端口号.接下来的4个字节是IP地址.

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

UPDATE

对于IPv6,情况类似:

sockaddr foo;
in_addr6 ip_address = ((sockaddr_in6)foo).sin6_addr;
Run Code Online (Sandbox Code Playgroud)

要访问单个字节,使用ip_address[0]... ip_address[15].

sockaddr_in6结构内部,前2个字节sa_data是端口号,接下来的4个字节是流信息,之后接下来的16个字节是IPv6地址.

警示[,然而,sockaddr_in6更大的sockaddr,所以从铸造时sockaddrsockaddr_in6,确保该地址的确是通过检查地址族IPv6地址foo.sa_family == AF_INET6.