ZetCode

Dart WebSocketTransformer

最后修改于 2025 年 4 月 4 日

Dart 中的 WebSocketTransformer 类提供了将 HTTP 连接升级到 WebSocket 连接的功能。它是 Dart dart:io 库中用于服务器端应用程序的一部分。

WebSocketTransformer 处理 WebSocket 握手协议并管理连接升级过程。当客户端支持时,它会将 HTTP 请求转换为 WebSocket 连接。

基本定义

WebSocketTransformer 是一个将 HTTP 连接升级到 WebSocket 连接的实用类。它实现了 WebSocket 协议的握手和连接管理。

主要功能包括协议协商、连接升级和消息流转换。它适用于服务器和客户端的 WebSocket 连接。

基本的 WebSocket 服务器

此示例展示了一个使用 WebSocketTransformer 的基本 WebSocket 服务器。

server.dart
import 'dart:io';
import 'dart:convert';

void main() async {
  final server = await HttpServer.bind('localhost', 8080);
  print('Server running on ${server.address}:${server.port}');

  await for (var request in server) {
    if (WebSocketTransformer.isUpgradeRequest(request)) {
      var socket = await WebSocketTransformer.upgrade(request);
      socket.add('Hello from server!');
      
      socket.listen((message) {
        print('Received: $message');
        socket.add('Echo: $message');
      });
    } else {
      request.response
        ..statusCode = HttpStatus.badRequest
        ..write('WebSocket upgrade required')
        ..close();
    }
  }
}

我们创建了一个升级 WebSocket 请求的 HTTP 服务器。Transformer 会自动处理协议升级。升级后,我们可以发送和接收消息。

$ dart server.dart
Server running on InternetAddress('127.0.0.1', IPv4):8080

处理多个连接

此示例演示了如何处理多个 WebSocket 连接。

server.dart
import 'dart:io';
import 'dart:async';

void main() async {
  final server = await HttpServer.bind('localhost', 8080);
  var clients = <WebSocket>[];

  await for (var request in server) {
    if (WebSocketTransformer.isUpgradeRequest(request)) {
      var socket = await WebSocketTransformer.upgrade(request);
      clients.add(socket);
      print('New client connected (${clients.length} total)');

      socket.listen((message) {
        print('Broadcasting: $message');
        for (var client in clients) {
          if (client != socket) {
            client.add('Client says: $message');
          }
        }
      }, onDone: () {
        clients.remove(socket);
        print('Client disconnected (${clients.length} remaining)');
      });
    } else {
      request.response
        ..statusCode = HttpStatus.badRequest
        ..write('WebSocket upgrade required')
        ..close();
    }
  }
}

我们维护一个已连接客户端的列表,并将消息广播给除发送者之外的所有客户端。onDone 回调可以干净地处理客户端断开连接。

$ dart server.dart
New client connected (1 total)
New client connected (2 total)
Broadcasting: Hello from client 1
Client disconnected (1 remaining)

自定义协议协商

此示例展示了在 WebSocket 升级期间的自定义协议协商。

server.dart
import 'dart:io';

void main() async {
  final server = await HttpServer.bind('localhost', 8080);

  await for (var request in server) {
    if (WebSocketTransformer.isUpgradeRequest(request)) {
      var protocols = request.headers['sec-websocket-protocol'];
      
      if (protocols != null && protocols.any((p) => p == 'chat-v1')) {
        var socket = await WebSocketTransformer.upgrade(
          request,
          protocol: 'chat-v1'
        );
        socket.add('Protocol chat-v1 accepted');
      } else {
        request.response
          ..statusCode = HttpStatus.badRequest
          ..write('chat-v1 protocol required')
          ..close();
      }
    } else {
      request.response
        ..statusCode = HttpStatus.badRequest
        ..write('WebSocket upgrade required')
        ..close();
    }
  }
}

我们在升级过程中检查特定的协议('chat-v1')。如果协议不支持,我们会拒绝连接。这实现了协议版本控制。

$ dart server.dart

错误处理

此示例演示了 WebSocket 连接中的正确错误处理。

server.dart
import 'dart:io';

void main() async {
  try {
    final server = await HttpServer.bind('localhost', 8080);
    print('Server started');

    await for (var request in server) {
      try {
        if (WebSocketTransformer.isUpgradeRequest(request)) {
          var socket = await WebSocketTransformer.upgrade(request);
          
          socket.handleError((error) {
            print('WebSocket error: $error');
            socket.close();
          });

          socket.listen((message) {
            if (message is! String) {
              throw FormatException('Only text messages supported');
            }
            print('Received: $message');
          }, onDone: () => print('Connection closed'));
        } else {
          request.response
            ..statusCode = HttpStatus.badRequest
            ..write('WebSocket upgrade required')
            ..close();
        }
      } catch (e) {
        print('Request handling error: $e');
        request.response
          ..statusCode = HttpStatus.internalServerError
          ..close();
      }
    }
  } catch (e) {
    print('Server error: $e');
  }
}

我们实现了多层错误处理:服务器启动、请求处理和 WebSocket 通信。这使得服务器更加健壮。

$ dart server.dart
Server started
Received: Hello
WebSocket error: FormatException: Only text messages supported
Connection closed

客户端 WebSocket

此示例展示了一个连接到我们服务器的 WebSocket 客户端。

client.dart
import 'dart:io';

void main() async {
  try {
    var socket = await WebSocket.connect('ws://:8080');
    print('Connected to server');
    
    socket.listen(
      (message) => print('Server says: $message'),
      onError: (error) => print('Error: $error'),
      onDone: () => print('Disconnected from server')
    );

    // Send messages every second
    var counter = 0;
    Timer.periodic(Duration(seconds: 1), (_) {
      socket.add('Message ${++counter}');
    });
  } catch (e) {
    print('Connection failed: $e');
  }
}

客户端连接到我们的 WebSocket 服务器并监听消息。它会定期发送消息以演示双向通信。

$ dart client.dart
Connected to server
Server says: Hello from server!
Server says: Echo: Message 1
Server says: Echo: Message 2
Disconnected from server

最佳实践

来源

Dart WebSocketTransformer 文档

本教程通过实际示例介绍了 Dart 的 WebSocketTransformer 类,展示了服务器实现、客户端通信以及 WebSocket 应用程序的最佳实践。

作者

我叫 Jan Bodnar,是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面有十多年的经验。

列出 所有 Dart 教程