<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 使用WebSockets 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提供的測試服務器](http://www.websocket.org/echo.html)。服務器將簡單地返回我們發送給它的相同消息! ### 步驟 1. 連接到WebSocket服務器。 2. 監聽來自服務器的消息。 3. 將數據發送到服務器。 4. 關閉WebSocket連接。 ### 1. 連接到WebSocket服務器 [web\_socket\_channel](https://pub.dartlang.org/packages/web_socket_channel) package 提供了我們需要連接到WebSocket服務器的工具. 該package提供了一個`WebSocketChannel`允許我們既可以監聽來自服務器的消息,又可以將消息發送到服務器的方法。 在Flutter中,我們可以創建一個`WebSocketChannel`連接到一臺服務器: ``` final channel = new IOWebSocketChannel.connect('ws://echo.websocket.org'); ``` ### 2. 監聽來自服務器的消息 現在我們建立了連接,我們可以監聽來自服務器的消息,在我們發送消息給測試服務器之后,它會返回相同的消息。 我們如何收取消息并顯示它們?在這個例子中,我們將使用一個[`StreamBuilder`](https://docs.flutter.io/flutter/widgets/StreamBuilder-class.html) Widget來監聽新消息, 并用一個Text Widget來顯示它們。 ``` new StreamBuilder( stream: widget.channel.stream, builder: (context, snapshot) { return new Text(snapshot.hasData ? '${snapshot.data}' : ''); }, ); ``` #### 工作原理 `WebSocketChannel`提供了一個來自服務器的消息Stream 。 該`Stream`類是`dart:async`包中的一個基礎類。它提供了一種方法來監聽來自數據源的異步事件。與`Future`返回單個異步響應不同,`Stream`類可以隨著時間推移傳遞很多事件。 該[`StreamBuilder`](https://docs.flutter.io/flutter/widgets/StreamBuilder-class.html) Widget將連接到一個Stream, 并在每次收到消息時通知Flutter重新構建界面。 ### 3. 將數據發送到服務器 為了將數據發送到服務器,我們會`add`消息給`WebSocketChannel`提供的sink。 ``` channel.sink.add('Hello!'); ``` #### 工作原理 `WebSocketChannel`提供了一個[`StreamSink`](https://docs.flutter.io/flutter/dart-async/StreamSink-class.html),它將消息發給服務器。 `StreamSink`類提供了給數據源同步或異步添加事件的一般方法。 ### 4. 關閉WebSocket連接 在我們使用`WebSocket`后,要關閉連接: ``` channel.sink.close(); ``` ### 完整的例子 ``` import 'package:flutter/material.dart'; import 'package:web_socket_channel/io.dart'; class WebSocketRoute extends StatefulWidget { @override _WebSocketRouteState createState() => new _WebSocketRouteState(); } class _WebSocketRouteState extends State<WebSocketRoute> { TextEditingController _controller = new TextEditingController(); IOWebSocketChannel channel; String _text = ""; @override void initState() { //創建websocket連接 channel = new IOWebSocketChannel.connect('ws://echo.websocket.org'); } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text("WebSocket(內容回顯)"), ), body: new Padding( padding: const EdgeInsets.all(20.0), child: new Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ new Form( child: new TextFormField( controller: _controller, decoration: new InputDecoration(labelText: 'Send a message'), ), ), new StreamBuilder( stream: channel.stream, builder: (context, snapshot) { //網絡不通會走到這 if (snapshot.hasError) { _text = "網絡不通..."; } else if (snapshot.hasData) { _text = "echo: "+snapshot.data; } return new Padding( padding: const EdgeInsets.symmetric(vertical: 24.0), child: new Text(_text), ); }, ) ], ), ), floatingActionButton: new FloatingActionButton( onPressed: _sendMessage, tooltip: 'Send message', child: new Icon(Icons.send), ), ); } void _sendMessage() { if (_controller.text.isNotEmpty) { channel.sink.add(_controller.text); } } @override void dispose() { channel.sink.close(); super.dispose(); } } ``` 上面的例子比較簡單,不再贅述。我們現在思考一個問題,假如我們想通過WebSocket傳輸二進制數據應該怎么做(比如要從服務器接收一張圖片)?我們發現`StreamBuilder`和`Stream`都沒有指定接收類型的參數,并且在創建WebSocket鏈接時也沒有相應的配置,貌似沒有什么辦法……其實很簡單,要接收二進制數據仍然使用`StreamBuilder`,因為WebSocket中所有發送的數據使用幀的形式發送,而幀是有固定格式,每一個幀的數據類型都可以通過Opcode字段指定,它可以指定當前幀是文本類型還是二進制類型(還有其它類型),所以客戶端在收到幀時就已經知道了其數據類型,所以flutter完全可以在收到數據后解析出正確的類型,所以就無需開發者去關心,當服務器傳輸的數據是指定為二進制時,`StreamBuilder`的`snapshot.data`的類型就是`List<int>`,是文本時,則為`String`。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看