我正在尝试通过 VPN 使用 IPv6 UDP 多播。我试过以下代码:
const dgram = require('dgram');
let sock = dgram.createSocket('udp6', {
reuseAddr: true
});
sock.on('message', (data, source) => {
console.log('on message', arguments);
});
sock.bind('36912', '2620:9b::1944:e598', () => {
sock.addMembership('ff02::1:3', '2620:9b::1944:e598');
});
setInterval(() => {
let buf = Buffer.from((new Date()).toString());
sock.send(buf, 0, buf.length, 36912, 'ff02::1:3');
}, 500);
脚本运行,我看到正在使用 Wireshark 发送/接收数据包,但两端都没有在控制台中显示它们。
我做错了什么?使用 IPv6 发送和接收基本多播的方法是什么?
最佳答案
Scope id -> 接口(interface)编号
在 IPv6 中,有一个地址的 scope_id 的概念,它应该指示 IP 地址的上下文,通常只表示它可以访问的接口(interface)。虽然作用域具有特定于操作系统的名称,但每个仅转换为接口(interface)编号,0 通常表示系统的默认值。
在 IPv6 多播中,此 scope_id 直接提供给 IP_ADD_MEMBERSHIP 和 IP_MULTICAST_IF,而不是像 IPv4 那样提供与接口(interface)关联的 ip。
v6 差异的封装平滑
node(通过 libuv)通过从您提供的“接口(interface)地址”中查找 scope_id 在 addMembership
中为您隐藏这种差异。
不幸的是,仅仅从一个 IP 开始并获得一个作用域并没有多大意义(作用域的全部意义在于 IP 在不同的作用域中可能有不同的用途。)所以 libuv 只能填充如果您在地址末尾明确提供范围,则使用 %[scope]
格式。
使用具有显式作用域的地址
解决方法似乎是:
sock.bind('36912', '::', () => {
sock.addMembership('ff02::1:3', '::%eth2');
...
sock.send(buf, 0, buf.length, 36912, 'ff02::1:3%eth2');
地点:
在 bind 中使用
::
(或无地址)是必要的,因为您正在组合接收,它将过滤此上的多播地址与需要正常地址的发送。使用
%[iface#]
强制此接口(interface)的作用域#。addMembership 的第二个参数实际上可以从任何地址开始,因为我们强制作用域,其余的被丢弃。
通常,发送套接字是分开的,并被赋予不同的端口或匿名端口,因为您可以配置的内容受到限制,或者由于套接字过于相似而有出现 EADDRINUSE 错误的危险。
关于node.js - 使用 Node.js 进行 IPv6 多播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38448369/