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

read bytes from a unix socket and print ip address in c

我有一个 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 字节长 header + 套接字地址结构的消息。我已经设法正确解码 header 但不是套接字地址结构。

TCPv4 (TCP/IPv4) 套接字由 32 位地址和 16 位端口号标识。 TCPv6 (TCP/IPv6) 套接字由 128 位地址和 16 位端口号标识。 sockaddr_ 结构比 C 库在内部使用(和要求)的内部信息多得多。您不能将这些结构从一个系统转移到另一个系统,并期望它们起作用。 (或者在另一端使 any 有点意义,真的。)

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

与其让客户端发送任何类型的 "sockaddr structure",它绝对应该发送 128 位 IPv6 地址,可能还有 16 位端口号.如果您以二进制格式发送这些,通常的做法是按网络字节顺序传输这些,即最高有效字节在前。

但是,我认为将它们作为字符串发送更简单、更可靠,例如使用格式 IPv6 [=14=] port [=14=] (即在地址后附加一个零字节,在端口后附加一个零字节)。这样你只需要一个指向地址的指针(node)和一个指向端口的指针(serv),你就可以使用getaddrinfo()重构所需的sockaddr_in6结构。

如果你非要发送二进制的地址和端口(比如保证一个fixed-size初始包),理论上你可以构造sockaddr_in6 手工构造。然而,那是 architecture-specific(byte-order 敏感),而且很脆弱。将 IPv6 地址转换为字符串(如果映射为 IPv4,则为 ::ffff:a.b.c.d,或者十六进制表示法为 aaaa:bbbb:cccc:dddd:eeee:ffff:gggg:hhhh),并将端口转换为十进制数,然后再次使用 getaddrinfo() 从中得到合适的套接字结构。