技术问题探讨:基于webrtc的隧道与打洞
Closed this issue · 4 comments
最近看了一个有趣的实现gRPC over WebRTC
jsmouret/grpc-over-webrtc: gRPC over WebRTC : https://t.cn/A6Ljno57
让我想到了可以基于WebRTC做隧道和打洞
webtorrent/webtorrent: ⚡️ Streaming torrent client for the web : https://t.cn/RNvDtGa
RTCTunnel - 实现通过WebRTC构建网络隧道 - Go开发社区 | CTOLib码库 : https://javascript.ctolib.com/rtctunnel-rtctunnel.html
实现WebRTC P2P连接 - 掘金 : https://juejin.im/post/6844903684539678734
感觉每次都要服务器来中转包,会不会开销太大
有没有可能让服务器只负责帮忙建立隧道,然后用户和用户可以直传数据
这个我们之前也考虑过,从技术上来说是可行的,主要还是和 NKN 的契合度问题。WebRTC 的打洞是依赖于中心化服务器的,而 NKN 是一个去中心化的网络。如果这个打洞服务和现在的转发一样,让所有节点提供的话,就会涉及到一个激励的问题,因为一个去中心化的系统里面大家是没有动机免费提供服务的;如果这个打洞服务让官方提供的话,这部分就变成一个中心化的服务了,这个就不太是和 NKN 做,而是适合一个第三方的地方做(我记得谷歌就提供这样的免费服务)。
目前我个人觉得比较好的方法是,把打洞的服务和逻辑包装成一个更高层的包,大概逻辑是:
- 检测是否是同一个局域网,是的话就直接连接;
- 如果不是同一个局域网,尝试打洞,如果成功的话就直接连接;
- 如果打洞失败,则采用 NKN 来传输;
以上逻辑是从最节省带宽的角度出发的,用户也有可能出于别的原因直接选择采用 NKN 来传输。
我觉得打洞和nkn可能不冲突,我希望是可以应用借助nkn构建直连的隧道(这样如果做大文件传输会更实用化)。
打洞的核心是知道自己的公网端口。只要在现有nkn协议中加入一个返回公网端口号的接口,那么应用层打洞就成为了可能。
这个在现有NKN网络协议中只是一句话的事情。
参考:关于TCP打洞技术(P2P)-大白菜-51CTO博客 : https://blog.51cto.com/dreamylights/1317914
A和B通过服务器分别拿到对方的外网IP和端口号(服务器获取,主动连接的,路由开的端口)
告诉服务器我们(A和B)都准备好了,这时服务器发出指令,准备P2P.
此时A和B分别去连接对方,就是,A去连接S_BS的外网端口,B去连接S_AS的外网端口,至少有一方可以连接到另一方,连接建立.
哈哈这种文章主要是科普的,打洞这个事情实现起来坑非常多,成功率也会随着网络情况和实现的细节有非常大的变化。
我就举一个例子吧,打洞这个首先是要考虑 NAT 类型的。比如很多路由器会用 TCP 连接的三元组、四元组信息来做过滤,也就是说你向服务器主动建立的连接,只有服务器的 IP,甚至是服务器的 IP + 端口发来的包才能通过,这种情况下简单的建立连接 - 告知 IP+端口的方式是不行的。所以打洞需要做的首先是 NAT 类型检测,不同的类型需要用不同的策略。
此外,这个外网端口和 NKN 的连接是不兼容的,也就是说,你用来打洞的连接和端口,是不能用来同时连接 NKN 网络的,所以他注定无法成为 NKN 的一个随手就可以做到的功能,而必须是专门来做的。
我这些说的都是能直接建立 TCP 连接和监听 TCP 端口的情况,而浏览器里面的情况就完全不一样了。浏览器不允许建立任意的 TCP 连接,也不允许监听 TCP 端口,只能用浏览器支持的 WebRTC 协议,这里面是包含了一整套专门的协议的,和上面这些不兼容。
实际上打洞需要考虑的情况是非常复杂的,里面的坑非常多,想要做好是很不容易的,随便做做的结果是成功率非常低。所以最合适的办法是找专门做打洞的库来做这件事。
嗯。明白。
我说的打洞不是替代nkn,而是一种优化。可以接受很多时候不成功的情况。
如果打洞不成功。那应用层面可以退回nkn继续传输数据。
不考虑浏览器的情况下,如何借助nkn打洞,可以这样搞。
假设nkn有某种接口支持告知发消息人的外网端口
a-b先建立nkn连接,这个就叫通讯信道吧。
为了打洞,a和b都再用随机种子重新生成一个nkn的连接,这个就叫打洞信道吧。
这个新连接的地址通过通讯信道相互告知。
a先在打洞信道b发一条消息,b收到的消息中包括了a的打洞信道外网端口
b收到消息之后,通过打洞信道的nkn回复a,这个回复也包含了a打洞信道的外网端口
基于浏览器搞会比较麻烦。需要nkn提供一个类似stun的服务。
不过先这样吧。以后再研究这些