将Dart升级客户端Socket为WebSocket

7

由于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);

这里的sock是Socket类型,socket是WebSocket类型,myListener是一个函数,当接收到消息时会打印一些调试语句。我没有收到错误,但也没有进入监听器 - 当我用以下代码替换前两行时,我可以进入监听器:

socket = await WebSocket.connect('ws://echo.websocket.org');    

我猜问题在于我的Socket 'sock'没有升级,而 WebSocket源代码中提到的构造函数明确说明:'从已升级的套接字创建WebSocket。'。
所以我的问题是,使用现有的Dart类是否可以将客户端(安全)Socket升级为升级的(安全)Socket?(这将允许将其转换为WebSocket实例)
1个回答

14

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

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

  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,
  );

3
非常感谢您的详细回答。对于ws,当使用request = await client.get('echo.websocket.org', 80, "")时,您的示例可以立即运行。对于任何对此感兴趣的人,该示例也适用于wss,只需使用Uri uri = Uri.parse("https://echo.websocket.org:443"); request = await client.getUrl(uri);请注意,在解析命令中我必须使用https而不是wss。 - CryptUser
1
现在StackOverflow将解析命令转换为链接。重要的是它应该以https://开头。 - CryptUser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接