什么是 Multiaddr
Multiaddr 最早的提出应该是 2014年6月2号在 Github 上这个 Issue: Binary packed network addresses 提出,后来在 mutiladdr 这里有了更加详细的描述。自称是可组合的面向未来的网络地址(Composable and future-proof network addresses)。
它将网络地址和各种协议组合,被描述为各种更加具体的协议和网络地址的组合:
- /ip4/1.2.3.4/tcp/1234 -> 表示 ipv4 协议,地址 1.2.3.4,端口 1234,TCP 连接
- /ip6/[::]/UDP/1235 -> 表示 ipv6 协议,地址 [::],端口 1234,UDP 连接
- /ip4/1.2.3.4/tcp/1234/tls/p2p/QmFoo -> 表示 ipv4 协议,地址 1.2.3.4,端口 1234,TCP 连接,P2P 的 PeerId 为 QmFoo
还可以组合成更加复杂的形式:
- /ip4/1.2.3.4/tcp/1234/p2p/QmR/p2p-circuit/p2p/QmA
- /ip6/[::]/UDP/1235/quic/tls/ws
等等可以随意组合的形式。
它要干嘛
从上面的例子可以看出,Multiaddr 有着比传统网络地址更多的信息,更友好的描述,可以直接描述一段网络地址的 IP 和端口外,还有网络协议,加密协议等等的信息。 从左到右看过去就能明白这段网络的组成由什么协议、甚至是什么加密算法、安全套见组成。是想形成一种更加通用的,对人阅读更友好,以及对机器解释友好的描述。
嗯,对人阅读更友好,从左到右可以直接阅读它的组成,用斜杠分隔出的各个部分,可以让人通过其格式理解它们各自的含义。比如将 /ip4/1.2.3.4/tcp/1234
分隔后为
- ip4 -> ipv4 协议
- 1.2.3.4 -> 用点分隔的四组 255 以内数字,是 ipv4 协议的 IP 地址
- tcp -> TCP 协议
- 1234 -> 65535 以内的数字,端口号
在 Multiaddr 里 ip4 或者 ip6 的 IP 协议后面一定会跟着 IP 地址,Tcp 或者 Udp 后面一定会跟着端口号。类似的 DNS 后面一定会跟着域名:/dns4/www.example.com
;P2p 后面一定会跟着 PeerId:/p2p/QmR
。所以很容易看出协议和它绑定的上下文,比如 ip4,它的 IP 地址就在它下一位。
这对机器的可理解性也有帮助,电脑在解释 Multiaddr 的时候会从右往左解释,并将从右边读取到的信息作为左边剩余信息的上下文。例如:/dns4/example.com/tcp/1234/tls/ws/tls
,从右往左读取的第一个信息是 tls
,表示使用 TLS 传输加密,剩下的 /dns4/example.com/tcp/1234/tls/ws
,右边第一个为 ws
,表示使用 WebSocket 连接,然后继续解释剩下的 /dns4/example.com/tcp/1234/tls
,右边的 tls(重复了对吧,先别管),表示 WebSocket 连接使用 TLS 传输层加密;接着是 /dns4/example.com/tcp/1234
,读取到 1234
,暂时不理解什么意思,会跟下一个 tcp
一起解释,解释为 TCP 连接,端口号为 1234;剩下的 /dns4/example.com
先读取到 example.com
,无法解释,跟端口一样作为上下文给下一个 dns4
,这下明白了,是作为 DNS 协议的一部分。
这种方式可以用来描述任意的网络协议,任何你想要组合的协议都可以往里面塞:/ip4/1.2.3.4/udp/12345/noise/quic/p2p/VM2T
,有着极强的包容性,人类可读以及机器可读的形式。以及可以很容易地在机器中表示为二进制的形式。
到目前位置它的实现有:
- js-multiaddr - stable
- go-multiaddr - stable
- java-multiaddr - stable
- haskell-multiaddr - stable
- py-multiaddr - stable
- rust-multiaddr - stable
- cs-multiaddress - alpha
- net-ipfs-core - stable
- swift-multiaddr - stable
- elixir-multiaddr - alpha
multiaddr
sub-module of Python module multiformats - alpha- dart-multiaddr - alpha
- Kotlin
- kotlin-multiaddr - stable
multiaddr
part of Kotlin project multiformat - alpha
看看就好
然而就我目前的体验来说,并不是说目前你有用到网络协议的写法都推荐为使用 Multiaddr 的方式。这种写法的可读性是非常好的,但是加大的程序实现的复杂性,有着各种语言提供的 multiaddr 库,但是使用 multiaddr 的程序,仍然需要自己解析出其中的协议。
程序工作量大
如果我想构建一个 Transport,里面封装了用于网络通讯的 ip协议、地址、端口等等信息,我使用了 multiaddr 作为构建的参数,定义了一个方法:
fn new_transport(multiaddr) -> Transport {}
这个对于 multiaddr 中协议的解析和构建的工作量是较大的。需要检查 multiaddr 里有 ip4 还是 ip6,获取到 IP 地址,再检查有 tcp 还是 udp,获取到 端口,才能在程序中构建出一个 Socket。如果有同时出现 ip4 和 ip6 的情况,要根据这类情况做出处理。对于 multiaddr 所支持的众多协议来说,处理的工作量是很大的。
程序耦合差
可读性友好但是对于程序不友好,实际开发过程中可能不如传统的方式。如果程序一开不知道自己要构造什么连接,希望作为参数传入,那么更好的做法应该是直接传入想要的参数,而不是传入一个 Multiaddr 后解析里面有什么。对于 /ip4/1.2.3.4/tcp/1234
,这种写法,完全可以用
{
'ipAddress': '1.2.3.4',
'port': '1234',
'protocol': 'tcp'
}
这种方式代替,因为 IP 地址格式的本身就说明了其要使用的 IP 协议是 v4 还是 v6,也可以少掉解析 Multiaddr 这一步骤。如果在加上其他相关的网络协议,tls
等,会增加构造 Transport
程序的复杂度。
总结
Multiaddr 是一种有有趣的地址方式,但是目前没有配套的成套工具,造轮子的成本也高,不推荐使用。
这篇博客对Multiaddr的概念进行了详细的解读,其中包括了Multiaddr的定义、用途、实现方式以及存在的问题。作者以清晰的逻辑和深入浅出的语言,将这一相对复杂的技术概念进行了逐一解析,使得读者能够更好地理解和掌握这一概念。
首先,我赞赏作者对Multiaddr的定义和用途的解释。作者通过举例和分析,清晰地解释了Multiaddr的组成和作用,使得读者能够快速理解Multiaddr的基本概念。同时,作者也对Multiaddr的实现方式进行了详细的介绍,列出了目前已有的实现方式,并对其稳定性进行了评价。
其次,我认同作者对Multiaddr存在问题的分析。作者指出,虽然Multiaddr在可读性上具有优势,但其在实际使用中可能会增加程序的复杂性,并可能导致程序的耦合性较差。这一观点深入且具有实际意义,对于理解Multiaddr的优缺点有很大帮助。
然而,我认为这篇博客在对Multiaddr的未来发展方向上的讨论较少。虽然作者指出了Multiaddr的一些问题,但并没有给出解决这些问题的具体建议或者可能的发展趋势。我认为,作者可以考虑从技术角度或者应用角度,对Multiaddr的未来发展方向进行一些探讨,这将使得这篇博客更具深度和前瞻性。
总的来说,这是一篇深度和广度都很好的技术博客,对于理解和掌握Multiaddr非常有帮助。希望作者在以后的写作中,可以继续保持这种深入浅出的风格,同时也能在对技术的未来发展方向上进行更多的探讨。