首页 > 解决方案 > 我需要在客户端套接字应用程序上使用 Dart 的惯用解决方案

问题描述

在 Dart 控制台中测试服务器套接字及其客户端。我发现我必须引入延迟的问题,await Future.delayed(Duration(milliseconds: 1));以便可以在我通过控制台请求消息的同时执行 sockect 的侦听周期。

我确信 Dart 中有更聪明的解决方案,但我还没有找到方法。

要运行代码,只需将代码复制/粘贴到一个文件中server.dartclient.dart运行它们。

这里的客户:

import 'dart:convert' show utf8;
import 'dart:io';

InternetAddress HOST = InternetAddress.loopbackIPv4;
const PORT = 7654;
void main() {
  Socket.connect(HOST, PORT).then((socket) async {
    print('connected to server $HOST$PORT');

    socket.handleError((error) {
      print('handleError $error');
    });
    socket.write('Hello, World from a client!');

    socket.cast<List<int>>().transform(utf8.decoder).listen(onData, onDone: () {
      print("Done");
    }, onError: (error) {
      print('onError: $error');
    });

    while (true) {
      await Future.delayed(Duration(milliseconds: 1));
      stdout.write("Enter your msg : ");
      var msg = stdin.readLineSync();
      socket.write(msg);
    }
  }).catchError((error) {
    print('catchError: $error');
  });
}

onData(data) {
  print('onData: ' + data);
}

这是一个请求发送到服务器的键盘输入的简单循环,这总是有效的,但是如果我删除await Future.delayed ...,我不会收到来自服务器的响应。

我对这种方法作为解决方案不太满意。是否有替代方案,可能是孤立的、精心打造的未来或溪流?

这里是服务器:

import 'dart:io';
import 'dart:convert' show utf8;

InternetAddress HOST = InternetAddress.loopbackIPv4;
const PORT = 7654;

void main() {
  ServerSocket.bind(HOST, PORT).then((ServerSocket srv) {
    print('serversocket is ready');
    srv.listen(handleClient);
  }).catchError(print);
}

void handleClient(Socket client) {
  var client_id =
      '${client.hashCode} => ${client.remoteAddress.address}:${client.remotePort}';

  print('Connection from: $client_id');
  client.write("Hello from Simple Socket Server!\n");

  // data from client:
  client.cast<List<int>>().transform(utf8.decoder).listen((msg) {
    print('${client.hashCode}: $msg');
    // Here switch msg
    client.write('Reply: ' + msg);
    //client.close();
  });
}

标签: socketsdartasync-awaitconsolefuture

解决方案


你有一个同步循环:while (true) { ... readLineSync() ... }. 整个循环是同步的,这意味着在循环结束之前不会运行其他代码(如果有条件true,则永远不会)。您必须在该同步循环期间放弃控制,以允许其他异步代码也运行。

因此,如果您可以将readLine线路更改为var msg = await stdin.readLine();,那么您在等待输入时不会阻止任何人。可悲的是你不能,没有 asynchronous readLine。因此,另一种方法是LineSplitter在 stdin 上使用 a 来异步获取行:

var stdinLines = ;
...

stdout.write("Enter your msg : ");
await for (var msg in stdin.transform(utf8.decoder).transform(const LineSplitter())) {
  socket.write(msg);
  stdout.write("Enter your msg : ");
}

推荐阅读