3

我花了几天时间寻找连接问题,但没有任何运气。我正在尝试使用 Kurento 实现一个相对简单的 one2one 调用。

下面你会看到一个Kurento的调试日志,其中有一个可以建立连接的情况和一个连接失败的情况。

如果您需要更多日志(例如客户端、信令服务器、tcpdump 或 Kurento 的跟踪日志,请告诉我,我会提供!)

非常感谢任何帮助或新的输入!

问题描述:

在大约 30% 的情况下,无法建立 WebRTC 连接。不幸的是,当可以建立连接时,我缺乏任何类型的模式,而当不能建立时,它似乎完全是随机的。我在同一个网络中,使用相同的设备,使用相同的 TURN 服务器,使用相同的信令协议,但在 30% 的情况下无法建立连接。

当我在本地运行应用程序时,它似乎更可靠地工作,几乎可以 100% 的时间建立连接(或者甚至可能 100% 的时间,我已经测试了很多次,我失去了轨道)。我使用 docker 在本地设置基础设施,并在不同的网络中运行不同的容器(TURN、Kurento、Signalling)以模拟生产部署。

我们在开发和生产环境中遇到相同的行为。在我们的开发环境中,我们绝对没有防火墙,所以这似乎不是问题。

我试图找到问题的原因:

大多数情况下,我一直在比较有效案例和无效案例的日志,但我没有发现它们之间有任何显着差异可以指出我的问题。

我已经通过 TURN 服务器(使用 Firefox 和 force_relay 标志)和直接通过 Kurento 测试了 WebRTC 连接,但在这两种情况下,大约 30% 的情况下连接失败。

我尝试过滤所有不是接力候选人的 ICE 候选人。

我已经嗅探了我们的信令服务器(也控制 Kurento)和 Kurento 之间的流量,以查看交换的 JSON RPS 消息的任何差异,但它们似乎基本相同。

我已经使用这个工具测试了我们的 STUN 和 TURN 服务器:https : //webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ 我得到了看起来正确的 serverreflexive 和 relay 候选

我已经嗅探了成功和不成功连接的客户端的流量,但可以发现显着差异

我已经简化了 Kurento 媒体管道(没有录制,没有集线器),但行为是一样的

我使用了不同的浏览器(Chrome、Firefox 和原生 iOS 实现),但行为是相同的

可以建立连接的情况的Kurento调试日志:

https://gist.github.com/omnibrain/2bc7ad54f626d278d3c8bac29767ac4c

无法建立连接的Kurento调试日志:

https://gist.github.com/omnibrain/f7caee04a5c6d77ea22a9ccfa95dd825

4

2 回答 2

7

经过几天的调试和几乎发疯,我们终于找到了问题的原因:

我们使用了 Socket.IO 的 Swift 客户端和 Socket.IO 的 Java Netty Socket.IO 服务器实现。客户端 (iOS) 使用长轮询与服务器 (Java) 通信。事实证明,Netty Socket.IO 服务器正在对 Swift Socket.IO 客户端的长轮询负载进行 URL 解码,但 Swift Socket.IO 客户端实际上并未对其进行 URL 编码。这意味着从 Swift Socket.IO 客户端发送的每个“+”在服务器上都被替换为“”(空格)。为什么这是个问题?因为客户端的SDP offer中包含一个ufrag,可以包含一个加号!因此,如果 SDP 包含“+”,则在服务器上将其替换为空格,这会导致 STUN ping 失败,因为无法验证消息完整性。

于 2019-01-24T20:49:02.310 回答
3

查看您的痕迹,您的工作案例选择候选人 10 ,然后选择候选人 7,非工作案例仅选择候选人 10。

kurento_logs_webrtc_working.txt

New candidate pair selected, local: 'candidate:10 1 UDP 335544831 10.10.36.134 50589 typ relay raddr 172.19.0.2 rport 9', remote: 'candidate:3993072200 1 UDP 41885695 10.10.36.134 53894 typ relay', stream_id: '1', component_id: 1
...
New candidate pair selected, local: 'candidate:7 1 UDP 1677722111 10.10.36.131 46842 typ srflx raddr 172.19.0.2 rport 46842', remote: 'candidate:266015763 1 UDP 2122260223 10.10.1.57 55125 typ host', stream_id: '1', component_id: 1

kurento_logs_webrtc_NOT_working.txt

new candidate pair selected, local: 'candidate:10 1 UDP 335544831 10.10.36.134 51280 typ relay raddr 172.19.0.2 rport 9', remote: 'candidate:3993072200 1 UDP 41885695 10.10.36.134 51287 typ relay', stream_id: '1', component_id: 1

我的第一个想法是您正在重新使用旧候选人,但端口已经改变。更改浏览器可能会更改候选编号,我没想到它们在运行之间是确定性的,所以我不得不看两次。

与日志有一个细微差别 - 出现之后而不是之前的非工作IceComponentStateChanged更改。我不知道这是否重要。connecting candidate:266015763

一般注意事项:

过去,当我们遇到几类问题时:

  • 在客户端,我们正在失去 ICE 候选人——一些候选人在我们准备好之前就被发送了,所以我们需要将他们排队。IIRC 在 SDP 报价中可能有一些候选人(或回答,抱歉已经有一段时间了),因此您的听众需要在开始之前做好准备。
  • 我们正在发送 OLD 候选 - 在信令服务器中使用了错误的重播元素来向客户端提供候选,这些不再有效。

我建议您使用带有chrome://webrtc-internals的 Chrome来提供帮助。ICE 候选问题在 webrtc-internals 中可见,因为您可以看到状态机遍历其状态。在我们的工作案例中,有更多的转变,而不是破碎的案例。

为三个 ice 事件添加客户端侦听器也很有帮助:

this.peer.peerConnection.oniceconnectionstatechange = this.logloglog.bind(this, this.peer.peerConnection);
this.peer.peerConnection.onicegatheringstatechange = this.logloglog.bind(this, this.peer.peerConnection);
this.peer.peerConnection.onsignalingstatechange = this.logloglog.bind(this, this.peer.peerConnection);

这可以让您了解谈判的进展情况,但基本上是chrome://webrtc-internals中的内容。

最后一点,这是我在日志记录部分使用的/etc/default/kurento-media-server


# ICE debug logging: uncomment to enable in KMS and in the 3rd-party library 'libnice'
# - Note: This can get very verbose, log size will explode in the long term
#export GST_DEBUG="$GST_DEBUG,kmsiceniceagent:5,kmswebrtcsession:5,webrtcendpoint:4"
export G_MESSAGES_DEBUG="libnice,libnice-stun"
export NICE_DEBUG="$G_MESSAGES_DEBUG"

我不记得它们是否比你用的更好,但我会把它扔在那里。

于 2019-01-24T20:25:18.023 回答