跳到主内容

与 WebSockets 通信

如何连接到 Web socket。

除了正常的 HTTP 请求之外,您还可以使用 WebSockets 连接到服务器。WebSockets 允许您无需轮询即可与服务器进行双向通信。

在此示例中,连接到由 Lob.com 赞助的 测试 WebSocket 服务器。服务器会回发您发送给它的相同消息。此配方使用以下步骤

  1. 连接到 WebSocket 服务器。
  2. 监听来自服务器的消息。
  3. 向服务器发送数据。
  4. 关闭 WebSocket 连接。

1. 连接到 WebSocket 服务器

#

web_socket_channel 包提供了您连接到 WebSocket 服务器所需的工具。

该包提供了一个 WebSocketChannel,允许您监听来自服务器的消息并向服务器推送消息。

在 Flutter 中,使用以下行创建一个连接到服务器的 WebSocketChannel

dart
final channel = WebSocketChannel.connect(
  Uri.parse('wss://echo.websocket.events'),
);

2. 监听来自服务器的消息

#

现在您已经建立了连接,请监听来自服务器的消息。

在向测试服务器发送消息后,它会回发相同的消息。

在此示例中,使用 StreamBuilder 部件监听新消息,并使用 Text 部件显示它们。

dart
StreamBuilder(
  stream: channel.stream,
  builder: (context, snapshot) {
    return Text(snapshot.hasData ? '${snapshot.data}' : '');
  },
),

工作原理

#

WebSocketChannel 提供了一个来自服务器的消息 Stream

Stream 类是 dart:async 包的基本组成部分。它提供了一种监听来自数据源的异步事件的方式。与仅返回单个异步响应的 Future 不同,Stream 类可以随着时间的推移传递许多事件。

StreamBuilder 部件连接到 Stream 并要求 Flutter 每次收到事件时使用给定的 builder() 函数重建。

3. 向服务器发送数据

#

要向服务器发送数据,请将消息 add()WebSocketChannel 提供的 sink

dart
channel.sink.add('Hello!');

工作原理

#

WebSocketChannel 提供了一个 StreamSink 以将消息推送到服务器。

StreamSink 类提供了一种通用的方法,用于将同步或异步事件添加到数据源。

4. 关闭 WebSocket 连接

#

完成 WebSocket 使用后,关闭连接

dart
channel.sink.close();

完整示例

#
dart
import 'package:flutter/material.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const title = 'WebSocket Demo';
    return const MaterialApp(
      title: title,
      home: MyHomePage(title: title),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _controller = TextEditingController();
  final _channel = WebSocketChannel.connect(
    Uri.parse('wss://echo.websocket.events'),
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Form(
              child: TextFormField(
                controller: _controller,
                decoration: const InputDecoration(labelText: 'Send a message'),
              ),
            ),
            const SizedBox(height: 24),
            StreamBuilder(
              stream: _channel.stream,
              builder: (context, snapshot) {
                return Text(snapshot.hasData ? '${snapshot.data}' : '');
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _sendMessage,
        tooltip: 'Send message',
        child: const Icon(Icons.send),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  void _sendMessage() {
    if (_controller.text.isNotEmpty) {
      _channel.sink.add(_controller.text);
    }
  }

  @override
  void dispose() {
    _channel.sink.close();
    _controller.dispose();
    super.dispose();
  }
}

Web sockets demo