Http协议是无状态的,只能由客户端主动发起,服务端再被动响应,服务端无法向客户端主动推送内容,并且一旦服务器响应结束,链接就会断开(见注解部分),所以无法进行实时通信。WebSocket协议正是为解决客户端与服务端实时通信而产生的技术,现在已经被主流浏览器支持,所以对于Web开发者来说应该比较熟悉了,Flutter也提供了专门的包来支持WebSocket协议。
注意:Http协议中虽然可以通过keep-alive机制使服务器在响应结束后链接会保持一段时间,但最终还是会断开,keep-alive机制主要是用于避免在同一台服务器请求多个资源时频繁创建链接,它本质上是支持链接复用的技术,而并非用于实时通信,读者需要知道这两者的区别。
WebSocket协议本质上是一个基于tcp的协议,它是先通过HTTP协议发起一条特殊的http请求进行握手后,如果服务端支持WebSocket协议,则会进行协议升级。WebSocket会使用http协议握手后创建的tcp链接,和http协议不同的是,WebSocket的tcp链接是个长链接(不会断开),所以服务端与客户端就可以通过此TCP连接进行实时通信。有关WebSocket协议细节,读者可以看RFC文档,下面重点看看Flutter中如何使用WebSocket。
在接下来例子中,将连接到由websocket.org提供的测试服务器 (opens new window),服务器将简单地返回发送给它的相同消息!
注意:由于 websocket.org 提供的测试服务器可能不能保证一直可用,如果读者在运行实例时发现连接不上,可以自己在本地编写并启动一个websocket服务去链接测试,关于如何编写websocket服务会涉及到服务端开发技术,读者可以自行在网上寻找相关教程,本书不做展开。
1 通信步骤
使用 WebSocket 通信分为五个步骤:
- 连接到WebSocket服务器。
- 监听来自服务器的消息。
- 将数据发送到服务器。
- 关闭WebSocket连接。
#1. 连接到WebSocket服务器
web_socket_channel (opens new window)package 提供了需要连接到WebSocket服务器的工具。该package提供了一个WebSocketChannel
允许既可以监听来自服务器的消息,又可以将消息发送到服务器的方法。
在Flutter中,可以创建一个WebSocketChannel
连接到一台服务器:
final channel = IOWebSocketChannel.connect('wss://echo.websocket.events');
注意:wss://echo.websocket.events 为 flutter.cn 提供的测试服务地址。
2. 监听来自服务器的消息
现在建立了连接,可以监听来自服务器的消息,在发送消息给测试服务器之后,它会返回相同的消息。
如何收取消息并显示它们?在这个例子中,将使用一个StreamBuilder
(opens new window)来监听新消息, 并用一个Text来显示它们。
StreamBuilder(
stream: widget.channel.stream,
builder: (context, snapshot) {
return Text(snapshot.hasData ? '${snapshot.data}' : '');
},
);
WebSocketChannel
提供了一个来自服务器的消息Stream
。该Stream
类是dart:async
包中的一个基础类。它提供了一种方法来监听来自数据源的异步事件。与Future
返回单个异步响应不同,Stream
类可以随着时间推移传递很多事件。该StreamBuilder
(opens new window)组件将连接到一个Stream
, 并在每次收到消息时通知Flutter重新构建界面。
#3. 将数据发送到服务器
为了将数据发送到服务器,会add
消息给WebSocketChannel
提供的sink。
channel.sink.add('Hello!');
WebSocketChannel
提供了一个StreamSink
(opens new window),它将消息发给服务器。
StreamSink
类提供了给数据源同步或异步添加事件的一般方法。
#4. 关闭WebSocket连接
在使用WebSocket
后,要关闭连接:
channel.sink.close();