Home > Software engineering >  How to manage multiple data from a StreamSubscription in dart?
How to manage multiple data from a StreamSubscription in dart?

Time:09-27

I want to send and retrieve multiple data from a client app.

I tried to do it this way:

(Server code)

void start() async{
  try{
    _server = await ServerSocket.bind('127.0.0.1', 1234);
    print('Waiting for connections');
    _server.listen(_handleClient);
  } catch(e) { await _server.close(); }
}

void _handleClient(Socket socket) async {
  late String request, username, password;
  socket.listen((data) => request = String.fromCharCodes(data));
  socket.write(_publicKey);
  socket.listen((data) => _clientPublicKey = _decrypt(String.fromCharCodes(data))); 
  socket.listen((data) => username = _decrypt(String.fromCharCodes(data)));
  socket.listen((data) => password = _decrypt(String.fromCharCodes(data)));

  var database = Database(username, password);

  switch (request) {
    case 'getItem':
      getItem(socket, database);
      break;
    case 'addItem':
      addItem(socket, database);
      break;
      [...]
  }
}

But I had this exception:

Waiting for connections
Unhandled exception:
Bad state: Stream has already been listened to.
#0      _StreamController._subscribe (dart:async/stream_controller.dart:635:7)
#1      _ControllerStream._createSubscription (dart:async/stream_controller.dart:786:19)
#2      _StreamImpl.listen (dart:async/stream_impl.dart:473:9)
#3      _Socket.listen (dart:io-patch/socket_patch.dart:2026:31)
#4      Server._handleClient (file:///D:/MyApps/Dart/my_netia_server/bin/Network/Server.dart:65:12)
#5      _RootZone.runUnaryGuarded (dart:async/zone.dart:1620:10)
#6      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#7      _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
[14 more...]

Process finished with exit code 255

The concern is that the function defined in listen is called each time a data is received. What I would like is that my code expect a data only when necessary. This will allow me to manage exactly the type of data received more simply (example: Object, String, int, ...)

CodePudding user response:

If you want to access independent events of a stream, one by one and when you're ready for them, I recommend the StreamQueue class from package:async.

You can also use the StreamIterator class from the dart:async platform library, but the StreamQueue has a much improved API.

Example use:

void _handleClient(Socket socket) async {
  var queue = StreamQueue(socket);
  
  String request = String.fromCharCodes(await queue.next);
  socket.write(_publicKey);
  _clientPublicKey = 
      _decrypt(String.fromCharCodes(await queue.next)));
  String username = 
      _decrypt(String.fromCharCodes(await queue.next)));
  String password = 
      _decrypt(String.fromCharCodes(await queue.next)));
  ...

That does assume that the individual response parts comes as independent events. That's what the original does, but it's not something I'd depend on.

More likely you want to accumulate bytes until you have enough, then parse the initial part of that.

  • Related