How to send a socket after receiving the previous socket result? Flutter Dart

Asked

Viewed 101 times

0

I am performing a socket communication using flutter in a Modbus equipment, I need to send several readings on the equipment, but one overlaps the other before the answer of the previous socket. I tried several ways, but I can’t fire automatically. Just in a few clicks on a button. I tried to add a loop. But it only sends several requests and only gets the last answer. But click the click works. Someone help me??

I’m using Dart and Flutter’s IO class.

sleep(const Duration(milliseconds: 300));

Uint8List request = preparaCMDUint8list(counter, 3, 1, '16', null);

await Future.wait([xhandle(request)]).then((_) {
  print('acabou o envio $_');
  // sleep(const Duration(milliseconds: 200));
  // setState(() {});
}).whenComplete(() {});


Uint8List request = preparaCMDUint8list(counter, 3, 1, '17', null);

await Future.wait([xhandle(request)]).then((_) {
  print('acabou o envio $_');
  // sleep(const Duration(milliseconds: 200));
  // setState(() {});
}).whenComplete(() {});

This is the function that sends the socket

Future xhandle(Uint8List _request) async {
  conectou = false;
  await Socket.connect(connectionProvider.getEnderecoIpConnect(),
          int.parse(await connectionProvider.getEnderecoPorta()))
      .then((Socket sock) {
    conectou = true;

    _socket = sock;
    _socket.listen(_onData,
        onError: errorHandler, onDone: doneHandler, cancelOnError: true);
    sleep(const Duration(milliseconds: 100));
  }).then((_) {
    conectou = true;
    print('Enviou, then do socket: $_request');
    print(_request); // so that your code runs AFTER the TCP/IP connection
    // _socket.write(_request);
    //counter++;
    print('Passou no timer eviou o request');
    print(DateTime.now());
    sleep(const Duration(milliseconds: 200));
    _socket.add(_request);
    sleep(const Duration(milliseconds: 400));

    _socket.close();
  }).whenComplete(() {
    if (!conectou) {
      conectou = false;
      _socket.close();
      print('erro do sockets');
      sleep(const Duration(milliseconds: 100));
    }
  });
}

There are other functions that I believe are not necessary, such as the onDone, onData and onError

Sleep are attempts to delay the code so one request does not swallow the other

  • What does it cost to edit a question and wait for it to be reopened? Try not to pollute the site...

1 answer

1

I don’t know the Modbus equipment, but in communication with equipment it is normal that with each data package sent you need to expect a response recognizing the receipt.

If that’s the case, your code doesn’t do that. You attach a callback to your socket but did not find in the code a synchronization that allows the next shipment to occur only after receiving the previous reply.

Other than that you need to make asynchronous programming work for you. A method marked as async serves to not need to use the API Future (calls to then()), then mixing the two can be the cause of your problems.

I tried to adjust your method xhandle to work this way. At first it opens the socket only if it is no longer open. Then it sends the data packet of the parameter _request and immediately awaits a response using await for.

I’m assuming the device only sends answers after receiving a socket command. If the equipment can randomly send other packages then its approach with _socket.listen is more appropriate, but in that case there needs to be some kind of synchrony in which, after sending a package, you expect the answer in your callback passed on _socket.listen and only releases the sending of a new package when the previous one gets reply.

Note that I have removed the closing part of the method socket xhandle. The idea is that once the socket is opened, it stays open until you no longer need it. Thus the socket closure should be elsewhere, probably in the screen output that calls this functionality.

Following example:

Socket _socket;
Future xhandle(Uint8List _request) async { 
  // ??= só atribui um novo valor a _socket se esse for nulo, senão ignora a chamada
  _socket ??= await Socket.connect(connectionProvider.getEnderecoIpConnect(),
          int.parse(await connectionProvider.getEnderecoPorta()));

  // Envia um pacote de dados via socket
  _socket.add(_request);

  // Aguarda uma resposta que deve acontecer 
  // como resultado do envio acima
  try {
    await for (final response in _socket) {
      // Processa response.
      // Se response foi o desejado para de esperar
      if (checaResposta(response)) {
        break;
      }
    }
  } catch (e) {
    // Houve erro ao obter resposta, trata aqui
  }
}
  • So, I did not solve this way, I created a timer that runs every 1 second. So it gives time to send and receive the package. And then confirm the received package with a global control variable. I trigger the next shipment. And so it will even make all shipments and receipts. Maybe it’s a scam, but it works.

  • I get it. If you’re not expecting any answers then it would be good to add an answer to your own question by describing your solution and marking your answer as accepted, so that other people find the solution more easily.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.