我有一个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字节长标头+套接字地址结构的消息。我设法正确解码了标头,但没有设法解码套接字地址结构。
答案 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}从中获取合适的套接字结构。