从unix套接字读取字节并在c中打印ip地址

时间:2016-01-21 11:32:37

标签: c unix-socket

我有一个Java客户端和一个通过unix套接字进行通信的C服务器。 我想从客户端向服务器发送IP地址。在服务器端,当我尝试解释从客户端收到的字节时,我得到[ 01 01 01 01 ]这是正确的,但是当我将ip_address打印到视频时,我得到0.0.0.0。我究竟做错了什么?我想我以某种方式以错误的方式施了地址。我需要实现IPv4映射的IPv6地址,这就是为什么我使用sockaddr_storage这是最常见的情况。

以下是我的一些代码摘录:

Java客户端:

OutputStream out;    
byte[] ipAddress = Inet6Address.getByName("1.1.1.1").getAddress();
out.write(ipAddress);

C服务器:

    struct sockaddr_storage * ip_address;
    n = read(rcv_sock, msg, PSIZE);
    printf("I recevied n bytes: %d\n", n);// i get 4 bytes
    print_bytes(msg, n);
    ip_address = (union sockaddr_storage *)msg;
    char str[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &(ip_address->__ss_padding), str, INET_ADDRSTRLEN);
    printf("ip_address = %s\n", str); //i get 0.0.0.0

特别是服务器需要一条包含28字节长标头+套接字地址结构的消息。我设法正确解码了标头,但没有设法解码套接字地址结构。

1 个答案:

答案 0 :(得分:0)

TCPv4(TCP / IPv4)套接字由32位地址和16位端口号标识。 TCPv6(TCP / IPv6)套接字由128位地址和16位端口号标识。 sockaddr_结构具有比C库内部使用(和必需)更多的内部信息。您无法将这些结构从一个系统转移到另一个系统,并希望它们能够正常工作。 (或者在另一端做出任何类型的感觉,真的。)

IPv4-mapped IPv6 addresses是IPv6地址,前80位为零,后跟16位,后跟32位IPv4地址。它们通常以IPv6格式编写为::ffff:a.b.c.d,其中a.b.c.d是映射到IPv6的IPv4地址。

不是让客户端发送任何类型的" sockaddr结构" ,它肯定应该发送128位IPv6地址,并且可能发送16位端口号。如果以二进制格式发送这些信息,通常的做法是以网络字节顺序传输这些信息,即最重要的字节优先传输。

但是,我认为将这些作为字符串发送更简单,更健壮,例如使用格式IPv6 \0 port \0(即附加)地址后面的零字节,以及端口后的另一个字节)。这样,您只需要一个指向地址(node)的指针和指向端口(serv)的指针,您就可以使用getaddrinfo()重建所需的sockaddr_in6结构。

如果必须以二进制形式发送地址和端口(例如,为了确保固定大小的初始数据包),理论上可以手动构建sockaddr_in6结构。但是,这是特定于体系结构(字节顺序敏感),而且是脆弱的。将IPv6地址转换为字符串要简单得多(如果是IPv4映射,则为::ffff:a.b.c.d,或以十六进制表示法为aaaa:bbbb:cccc:dddd:eeee:ffff:gggg:hhhh,将端口转换为十进制数字,并再次使用{{3}从中获取合适的套接字结构。