实施协议-如何与服务器对话?

时间:2019-12-19 01:11:26

标签: dart

我正在尝试在Dart中实现协议。

基本上,我需要创建一些类似于ask_for_help (见下文)的方法。

这是我到目前为止的代码:

const int DEFAULT_TIMEOUT = 3;

class MySocket {
  /// The host server
  String _host;

  /// The TCP port number
  int _port;

  /// The status of the socket (connected or not)
  bool _isConnected = false;

  /// The connection timeout
  Duration _timeout;

  /// The connected socket (if any, see [_isConnected])
  Socket _socket;

  /// Establish a connection with the [host] on given [port]
  ///
  /// Throws a [SocketException] if connection cannot be established.
  Future<void> connect(String host, int port,
      {int timeout = DEFAULT_TIMEOUT}) async {
    _host = host;
    _port = port;

    _timeout = Duration(seconds: timeout);

    _socket = await Socket.connect(host, port, timeout: _timeout);
    _isConnected = true;

    _socket.listen(default_handler);
  }

  /// Send [cmd] command to the connected server
  void send_request(String cmd) {
    _socket.writeln(cmd);
  }

  /// Close the connection with the server
  void close() {
    _isConnected = false;
    _socket.close();
  }

  void ask_for_help() {
    var cmd = 'HELP';
    send_request(cmd);
    // Start listening to the socket
    // Wait for a response
    // Stop listening to the socket
    // Consume response from the Stream
    // Do something with that response (e.g print it on stdout)
  }
}

void default_handler(Uint8List message) {
  print('----- RESPONSE STARTS HERE -----');
  print(String.fromCharCodes(message).trim());
  print('----- RESPONSE ENDS HERE -----');
}

然后我有几个问题:

  1. 如何使ask_for_help监听套接字,直到它收到响应?
  2. 如何确保每种方法都将读取正确的响应,而不是另一种? (如果在服务器应答之前发送了多个请求)

关于第二个问题的说明:使用以上代码,当我发送多个请求且它们之间没有延迟时,所有响应都汇集在一起​​。这意味着我无法确定应该使用哪个函数来处理它。

欢迎任何建议。

1 个答案:

答案 0 :(得分:0)

拥有一项进行实际通信的服务(即SocketService)。当某人想通过套接字发送消息时,它可以调用消息。然后公开一个流对象,其他人可以订阅该流对象以侦听消息。

class SocketService {
  SocketService _instance;
  SocketService._();
  factory SocketService() {
    if (_instance == null) _instance = SocketService._();
    return _instance;
  }

  final _streamController = StreamController.broadcast();
  Stream get stream => _streamController.stream;

  Future init() async {
    // TODO: Initialize the socket connection
    // TODO: Setup incoming messages to get routed to _onMessage
  }

  void _onMessage(dynamic message) {
    _streamController.add(message);
  }

  StreamSubscription listen(void Function(dynamic) onMessage) {
    return stream.listen(onMessage);
  }

  void sendMessage(dynamic message) {
    // TODO: Send the message across the socket connection
  }

  void close() {
    // TODO: Close the socket connection
    _streamController.close();
  }
}

其他地方:

// Listen for incoming messages
var subscription = SocketService().subscribe((msg) {
  print(msg);
});

// Send a message
SocketService().sendMessage('This is a message');

特定于套接字的东西会有所不同,具体取决于您用来处理连接本身的软件包。上面将这种服务类作为过于简单的单例来实现,以使您理解要点,但是您可以自己使用所需的任何模式来实现此概念。

在子容器端,您还可以利用流转换来过滤除您实际感兴趣的消息以外的任何消息:

// Filter stream messages so only messages 
// that are string objects get printed
var subscription = SocketService().stream.where((msg) => msg is String).listen(msg) {
  print(msg);
});

传递给where方法的过滤谓词可以实现您想要的任何条件。

仅供参考:如果您要在流和流操纵方面做很多事情,我强烈建议您使用rxdart软件包。与使用原始流相比,它使处理流更容易,更直观。