等待 WebSocket 响应

huangapple go评论54阅读模式
英文:

Dart: Wait for WebSocket reponse

问题

在我的代码中,我通过WebSocket建立了与服务器的连接。现在有一种情况,即服务器响应我的消息,我想处理这个响应。但是,我找不到一个好的方法来解决这个问题。

我的方法是通过listen方法将WebSocket的响应写入一个列表,并在发送后查询这个列表(请参见代码)。我在循环中多次调用sendAndWaitForAnswer方法,因为我必须向服务器发送多个初始化请求。问题是WebSocket在超时之后才将答案写入rxData,而sendAndWaitForAnswer已经被超时终止(请参见输出)。有没有人有办法等待WebSocket的答案?

我知道正常的HTTP请求可能更好,因为你可以直接得到响应,但不幸的是我不能改变服务器。

这不是用于Flutter应用程序。

打印输出:

发送数据并等待响应
发送数据并等待响应
发送数据并等待响应
发送数据并等待响应
发送数据并等待响应
新的WebSocket消息:... // 事件消息用 "..." 简化
新的WebSocket消息:...
新的WebSocket消息:...
新的WebSocket消息:...
新的WebSocket消息:...

我想要的是:

发送数据并等待响应
新的WebSocket消息:...
找到数据
发送数据并等待响应
新的WebSocket消息:...
找到数据
发送数据并等待响应
新的WebSocket消息:...
找到数据
发送数据并等待响应
新的WebSocket消息:...
找到数据

简化的代码:

class Connection {
	late IOWebSocketChannel webSocketChannel;
	var rxData = [];

	connect() {    
		webSocketChannel = IOWebSocketChannel.connect(  
			Uri.parse("ip地址"),  
			pingInterval: Duration(seconds: 30),  
		);  
	  
		webSocketChannel.stream.listen((event) {  
			print("新的WebSocket消息:$event");  
			rxData.add(event);  
		});   
	}

	send(opcode, parameters) {  
		Map<String, dynamic> dataSendMap = {  
			"opcode": opcode,  
			"parameters": parameters,  
		};  
		String jsonData = json.encode(dataSendMap);  
		webSocketChannel.sink.add(jsonData);  
	}

	sendAndWaitForAnswer(dataOpt, dataParam) {
		print("发送数据并等待响应");
		send(dataOpt, dataParam);
        timeout = 5;
        int startTime = DateTime.now().millisecondsSinceEpoch ~/ Duration.millisecondsPerSecond;
		while((DateTime.now().millisecondsSinceEpoch ~/ Duration.millisecondsPerSecond) - startTime < timeout) {
			for (var data in rxData) {  
				if (data['opcode'] == dataOpt) {  
                    print("找到数据");
					answer = data;  
					rxData.remove(data);  
				}  
			}
		}
		return answer;
	}
}
英文:

in my code I am establishing a server connection via a WebSocket. Now there is the case that the server responds to my message and I want to process this response. However, I can't find a good approach on how to solve this.

My approach was to write the response from the WebSocket into a list via the listen method and to query this list after sending (see code). I call the sendAndWaitForAnswer method several times in a loop, because I have to send several requests to the server for initialisation. The problem is that the WebSocket writes the answers to rxData only after sendAndWaitForAnswer has already been terminated by the timeout (see output). Does anyone have an idea how to wait for the answer from the WebSocket?

I know that normal HTTP requests would probably be better, since you have a response directly, but unfortunately I can't change the server.

Its not for a Flutter app.

Print output:

send data and wait for response
send data and wait for response
send data and wait for response
send data and wait for response
send data and wait for response
new webSocket Message: ...     // event message simplified with &quot;...&quot;
new webSocket Message: ...
new webSocket Message: ...
new webSocket Message: ...
new webSocket Message: ...

What i want:

send data and wait for response
new webSocket Message: ...
data found
send data and wait for response
new webSocket Message: ...
data found
send data and wait for response
new webSocket Message: ...
data found
send data and wait for response
new webSocket Message: ...
data found

Simplified Code:

class Connection {

	late IOWebSocketChannel webSocketChannel;
	var rxData = [];

	connect() {    
		webSocketChannel = IOWebSocketChannel.connect(  
			Uri.parse(&quot;ipAdress&quot;),  
			pingInterval: Duration(seconds: 30),  
		);  
	  
		webSocketChannel.stream.listen((event) {  
			print(&quot;new webSocket Message: $event&quot;);  
			rxData.add(event);  
		});   
	}

	send(opcode, parameters) {  
		Map&lt;String, dynamic&gt; dataSendMap = {  
			&quot;opcode&quot;: opcode,  
			&quot;parameters&quot;: parameters,  
		};  
		String jsonData = json.encode(dataSendMap);  
		webSocketChannel.sink.add(jsonData);  
	}

	sendAndWaitForAnswer(dataOpt, dataParam) {
		print(&quot;send data and wait for response&quot;);
		send(dataOpt, dataParam);
        timeout = 5;
        int startTime = DateTime.now().millisecondsSinceEpoch ~/ Duration.millisecondsPerSecond;
		while((DateTime.now().millisecondsSinceEpoch ~/ Duration.millisecondsPerSecond) - startTime &lt; timeout) {
			for (var data in rxData) {  
				if (data[&#39;opcode&#39;] == dataOpt) {  
                    print(&quot;data found&quot;);
					answer = data;  
					rxData.remove(data);  
				}  
			}
		}
		return answer;
	}
}

答案1

得分: 1

在Dart中处理WebSocket响应,您可以使用web_socket_channel包,它提供了一种便捷的方式来建立WebSocket连接和处理传入的消息。以下是如何处理WebSocket响应的示例:

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

class MyWebSocketWidget extends StatefulWidget {
  @override
  _MyWebSocketWidgetState createState() => _MyWebSocketWidgetState();
}

class _MyWebSocketWidgetState extends State<MyWebSocketWidget> {
  final channel = IOWebSocketChannel.connect('wss://your-websocket-url.com');

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebSocket Demo'),
      ),
      body: StreamBuilder(
        stream: channel.stream,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            // 处理接收到的数据
            final response = snapshot.data as String;
            // 处理响应
            // ...
          }
          return Center(
            child: CircularProgressIndicator(),
          );
        },
      ),
    );
  }
}

希望这对您有所帮助。如果您有任何其他问题,请随时提出。

英文:

To process WebSocket responses in Dart, you can use the web_socket_channel package, which provides a convenient way to establish WebSocket connections and handle incoming messages. Here's an example of how you can handle WebSocket responses:

import &#39;package:flutter/material.dart&#39;;
import &#39;package:web_socket_channel/web_socket_channel.dart&#39;;
import &#39;package:web_socket_channel/io.dart&#39;; 
class MyWebSocketWidget extends StatefulWidget {
  @override
  _MyWebSocketWidgetState createState() =&gt; _MyWebSocketWidgetState();
}

class _MyWebSocketWidgetState extends State&lt;MyWebSocketWidget&gt; {
  final channel = IOWebSocketChannel.connect(&#39;wss://your-websocket-url.com&#39;);

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(&#39;WebSocket Demo&#39;),
      ),
      body: StreamBuilder(
        stream: channel.stream,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            // Process the received data
            final response = snapshot.data as String;
            // Do something with the response
            // ...
          }
          return Center(
            child: CircularProgressIndicator(),
          );
        },
      ),
    );
  }
}

答案2

得分: 0

I found a solution with async/await and a Completer. Here is my simplified Code:

  Completer completer = Completer();
  late IOWebSocketChannel webSocketChannel;

  void connect(String ip, {int port = 1234}) {
    String address = "ws://$ip:$port/test/";
    webSocketChannel = IOWebSocketChannel.connect(
      Uri.parse(address),
    );
    webSocketListen();
  }

  void webSocketListen() {
    webSocketChannel.stream.listen(
      (event) {
        completer.complete(event);

      },
    );
  }
  
  sendAndWaitForAnswer(data) async {
    _send(data);
    var answer = await completer.future;
    completer = Completer();
    answer = jsonDecode(answer);
    return answer;
  }

  _send(data) {
    Map<String, dynamic> dataSendMap = {
      "data": opcode,
    };
    String jsonData = json.encode(dataSendMap);
    webSocketChannel.sink.add(jsonData);
  }

Please note that I've removed the HTML entities like &quot; and &lt; for better code readability.

英文:

I found a solution with async/await and a Completer. Here is my simplified Code:

  Completer completer = Completer();
  late IOWebSocketChannel webSocketChannel;

  void connect(String ip, {int port = 1234}) {
    String address = &quot;ws://$ip:$port/test/&quot;;
    webSocketChannel = IOWebSocketChannel.connect(
      Uri.parse(address),
    );
    webSocketListen();
  }

  void webSocketListen() {
    webSocketChannel.stream.listen(
      (event) {
        completer.complete(event);

      },
    );
  }
  
  sendAndWaitForAnswer(data) async {
    _send(data);
    var answer = await completer.future;
    completer = Completer();
    answer = jsonDecode(answer);
    return answer;
  }

  _send(data) {
    Map&lt;String, dynamic&gt; dataSendMap = {
      &quot;data&quot;: opcode,
    };
    String jsonData = json.encode(dataSendMap);
    webSocketChannel.sink.add(jsonData);
  }

huangapple
  • 本文由 发表于 2023年5月17日 17:55:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76270810.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定