测试一个可能长时间保持打开状态的 WebSocket

主要观点:作者在多年未改动的 Go 代码中遇到一个 WebSocket 连接长时间保持打开的 bug,通过调查发现是由于在 select 语句中使用默认 case 且无读取超时导致,WebSockets 开始是普通 HTTP 请求,连接结束时应发送关闭帧,若未收到则会长时间等待,测试该 bug 需手动在 TCP 上进行请求,解决该 bug 可设置读取超时或在 goroutine 中处理读取并返回结果。

关键信息:

  • 代码中有一个超时设置为 1 秒,但有时连接会在 12 小时后仍保持打开。
  • 代码中的 bug 在于使用默认 case 且无读取超时,导致连接不会被中断。
  • WebSockets 开始是普通 HTTP 请求,连接结束时应发送关闭帧,若未收到则会长时间等待。
  • 测试该 bug 需手动在 TCP 上进行请求,设置超时并检查连接是否关闭。
  • 解决 bug 可设置读取超时或在 goroutine 中处理读取并返回结果。

重要细节:

  • 初步调查发现该 bug 仅发生在特定 VPN 的用户中。
  • 代码中的 for 循环存在问题,默认 case 会在超时前一直运行,若未设置读取超时,conn.ReadMessage()会一直等待。
  • WebSockets 是双向的,与 TCP 类似,开始是普通 HTTP 请求,之后切换为二进制协议。
  • 测试中通过打开 TCP 连接、发送升级请求、设置读取超时并定期检查连接状态来模拟 bug 情况。
  • 解决 bug 时可设置读取超时或在 goroutine 中处理读取并返回结果,当超时或读取完成时关闭连接。
  • 该 bug 可能隐藏在 WebSockets 代码和其他网络代码的很多地方,容易被忽略。
  • 感谢 Erika Rowland 和 Dan Reich 提供反馈。
  • 文中提到了一些相关的参考资料和注释,如通常的 HTTP 请求模式、WebSocket 维基百科文章、Go 中发送 HTTP 请求的方式、测试中超时设置的注意事项等。
阅读 10
0 条评论