Ad

Client Only Listens To Server When Sends A Message

- 1 answer

I'm implementing socket. Two clients connect to the server with no problem, when client1 sends a message to the server, the server publishes it to every other client (which in this case is client2). but client2 won't get the message unless it sends a message. It seems the listener of the client doesn't work. Obviously, I want client2 to get the message from client1 instantly.

enter image description here

here is my sever code:

import 'dart:io';
import 'dart:typed_data';

void main() async {
  // bind the socket server to an address and port
  MySocket mySocket = MySocket();
  await mySocket.init();
}

class MySocket {
  ServerSocket? server;
  List<Socket> clients = [];

  //initialize the socket
  init() async {
    server = await ServerSocket.bind("192.168.0.112", 4000);
    // listen for client connections to the server
    server!.listen((client) {
      handleConnection(client);
      addClient(client);
    });
  }

  void handleConnection(Socket client) async {
    print('Connection from'
        ' ${client.remoteAddress.address}:${client.remotePort}');

    // listen for events from the client
    client.listen(
      // handle data from the client
      (Uint8List data) async {
        await Future.delayed(Duration(seconds: 1));
        final message = String.fromCharCodes(data);
        print(message);
        publish(message, client);
      },

      // handle errors
      onError: (error) {
        print(error);
        client.close();
      },

      // handle the client closing the connection
      onDone: () {
        print('Client left');
        client.close();
      },
    );
  }

  void addClient(Socket client) {
    //if client doesn't already exist add it to the list of clients
    if (!clients.any((element) =>
        '${client.remoteAddress.address}:${client.remotePort}' ==
        '${element.remoteAddress.address}:${element.remotePort}')) {
      clients.add(client);
    }
  }

  void publish(String message, Socket client) {
    //write the message to every client except the author of it
    clients.forEach((element) async {
      if ('${client.remoteAddress.address}:${client.remotePort}' !=
          '${element.remoteAddress.address}:${element.remotePort}') {
        element.write(message);
      }
    });
  }
}

here is my client-side code:

import 'dart:io';
import 'dart:typed_data';

void main() async {
  //gets the username
  String name = '';
  while (name.isEmpty) {
    print('Enter your name: ');
    name = stdin.readLineSync() ?? '';
  }

  // connect to the socket server
  final socket = await Socket.connect("192.168.0.112", 4000);
  print('Connected to: ${socket.remoteAddress.address}:${socket.remotePort}');


  // listen for responses from the server
  socket.listen(
    // handle data from the server
    (Uint8List data) {
      final serverResponse = String.fromCharCodes(data);
      print('$serverResponse');
    },

    // handle errors
    onError: (error) {
      print(error);
      socket.destroy();
    },

    // handle server ending connection
    onDone: () {
      print('Left server.');
      socket.destroy();
    },
  );


  // sending messages to the server
  String message = "";
  while (message != "exit") {
    message = stdin.readLineSync() ?? '';
    await sendMessage(socket, name, message);
  }
  socket.close();
}


Future<void> sendMessage(Socket socket, String name, String message) async {
  socket.write('$name: $message');
  await Future.delayed(Duration(seconds: 2));
}

Thank you in advance.

Ad

Answer

The issue is because stdin.readLineSync() in your client blocks the current thread. You can get around this by spawning an isolate to handle that portion of the code, so that it does not block the socket.listen from printing out the responses from the server.

See updated client code below:

import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data';

void main() async {
  //gets the username
  String name = '';
  while (name.isEmpty) {
    print('Enter your name: ');
    name = stdin.readLineSync() ?? '';
  }

  // connect to the socket server
  final socket = await Socket.connect("192.168.0.112", 4000);
  print('Connected to: ${socket.remoteAddress.address}:${socket.remotePort}');

  // listen for responses from the server
  socket.listen(
    // handle data from the server
    (Uint8List data) {
      final serverResponse = String.fromCharCodes(data);
      print('$serverResponse');
    },

    // handle errors
    onError: (dynamic error) {
      print(error);
      socket.destroy();
    },

    // handle server ending connection
    onDone: () {
      print('Left server.');
      socket.destroy();
    },
  );

  final receive = ReceivePort();
  final isolate = await Isolate.spawn(readMessages, receive.sendPort);
  await for (final message in receive) {
    if (message == 'exit') break;
    await sendMessage(socket, name, message as String);
  }

  socket.close();
}

void readMessages(SendPort port) {
  String message = '';
  while (message != 'exit') {
    message = stdin.readLineSync() ?? '';
    port.send(message);
  }
  Isolate.exit(port);
}

Future<void> sendMessage(Socket socket, String name, String message) async {
  socket.write('$name: $message');
  await Future<void>.delayed(Duration(seconds: 2));
}

Ad
source: stackoverflow.com
Ad