我习惯使用 IPv4 编写代码,您可以使用
recvfrom
和 sendto
回复发送者,但是使用 IPv6,事情似乎有点棘手。 虽然我现在使用的是 Linux,但这个问题更多的是关于 IPv6 和一般本地地址。
计算机 A:fe80::eabf:bbff:cae0:8d3e 计算机 B: fe80::da3a:ddff:fee3:e257
要从计算机 B ping 计算机 A,我可以:
ping fe80::eabf:bbff:cae0:8d3e%eth0
或者将数据包发送到计算机 A,我可以:
echo "xyz" | nc fe80::eabf:bbff:cae0:8d3e%eth0 5353 -u -w 1
在计算机A上,我可以执行:
struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ANY_INIT,
.sin6_port = htons( MDNS_PORT )
};
sd6 = socket( AF_INET6, SOCK_DGRAM, 0 );
if ( bind( sd6, (struct sockaddr *)&sin6, sizeof(sin6) ) == -1 ); // Checks (didn't fail)
...
struct sockaddr sender = { 0 };
socklen_t sl = sizeof( sender );
int r = recvfrom( sock, buffer, sizeof(buffer), 0, (struct sockaddr*) &sender, &sl );
printf( "%d / %d\n", r, sender.sin6_family );
for( i = 0; i < sl; i++ )
printf( "%02x ", ((uint8_t*)&sender)[i] );
printf( "\n" );
sendto( sock, "hello", 5, 0, &sender, sl );
并且,从上面发送 nc 线时我得到以下信息:
4 / 10
0a 00 a9 89 00 00 00 00 fe 80 00 00 00 00 00 00 da 3a dd ff fe e3 e2 57 02 00 00 00
这是完全有道理的 - 这是计算机 B 的地址。但是,很多时候,数据包从未被传输。 我认为这是因为有时如果我从计算机 A 冷 ping 计算机 B,这些 ping 也永远不会通过。
如果没有指定接口的映射,似乎 IPv6 始终无法解析。
如何使对 IPv6 数据包的回复通过它们来自的接口返回?
在沿着
recvmsg
的路径走得太远之前,这似乎不适用于 IPv6,就像 IPv4 一样,对于 IPv6,当使用 recvmsg
时,没有控制负载,因此无法真正回复与 sendto
有什么想法吗? 有建议吗?
由于我对 C 缺乏经验,这 50% 是猜测,但是:
如果将变量声明为“struct sockaddr”,那么它比存储在其中的 sockaddr_in6 小,导致每次 receivevfrom() 尝试在其中放置 inet6 地址时发生缓冲区溢出。要么 recvfrom() 覆盖结构之外的另一个变量(也许它在“sl”变量中放入垃圾?),或者相反。
您想要的通用“适合所有人”类型是
struct sockaddr_storage
。
(是的,sin6_scope_id很重要,但是recvfrom()总是填充它——它认为它以任何方式填充sockaddr_in6。)