Dart 将客户端 Socket 升级为 WebSocket

Cry*_*ser 3 certificate websocket dart flutter

由于Dart 中的WebSocket不允许直接设置SecurityContext(我需要进行证书检查),因此我想与SecureSocket实例建立连接,然后使用 WebSocket.fromUpgradedSocket 构造函数从中创建一个 WebSocket 实例。

这个想法最初是在这里提出的。

但是,我没有让它与以下代码一起工作(虽然我想要 wss,但 ws 甚至不起作用):

sock = await Socket.connect('ws://echo.websocket.org', 80);
socket = WebSocket.fromUpgradedSocket(sock, serverSide: false);
socket.listen(myListener);
// Send some dummy data
var list = utf8.encode("hello");
var data = list is Uint8List ? list : Uint8List.fromList(list);
socket.add(data);
Run Code Online (Sandbox Code Playgroud)

这里 sock 是 Socket 类型,socket 是 WebSocket 类型,而 myListener 是一个函数,它在接收到消息时打印一些调试语句。我没有收到错误消息,但我也没有进入侦听器 - 当我用这一行替换前两行时,我会这样做:

socket = await WebSocket.connect('ws://echo.websocket.org');    
Run Code Online (Sandbox Code Playgroud)

我认为问题在于我的 Socket 'sock' 没有升级,而上述构造函数的WebSocket 源代码明确指出:'从已经升级的套接字创建一个 WebSocket。'。

所以我的问题是,现有的 Dart 类是否有可能将客户端 (Secure-)Socket 升级到升级后的 (Secure-)Socket?(然后允许将其转换为 WebSocket 实例)

Ric*_*eap 5

使用HttpClient建立初始 http(s) 连接,然后detach建立套接字。这是一个使用 http 的示例。你应该能够适应https。请注意初始连接是如何通过 http 建立的,但通过添加适当的请求标头进行升级。(您需要根据您的 websocket 服务器所需的安全方案调整标头。)

  Random r = new Random();
  String key = base64.encode(List<int>.generate(8, (_) => r.nextInt(255)));

  HttpClient client = HttpClient(/* optional security context here */);
  HttpClientRequest request = await client.get('echo.websocket.org', 80,
      '/foo/ws?api_key=myapikey'); // form the correct url here
  request.headers.add('Connection', 'upgrade');
  request.headers.add('Upgrade', 'websocket');
  request.headers.add('sec-websocket-version', '13'); // insert the correct version here
  request.headers.add('sec-websocket-key', key);

  HttpClientResponse response = await request.close();
  // todo check the status code, key etc
  Socket socket = await response.detachSocket();

  WebSocket ws = WebSocket.fromUpgradedSocket(
    socket,
    serverSide: false,
  );
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢您的详细回答。对于 ws,您的示例在使用 request = wait client.get('echo.websocket.org', 80, ""); 时开箱即用。对于任何感兴趣的人,该示例也可以通过使用 Uri uri = Uri.parse("https://echo.websocket.org:443"); 与 wss 配合使用。请求=等待client.getUrl(uri); 请注意,我必须在解析命令中使用 https,而不是 wss。 (4认同)