Dart UDP客户端/服务器

8
我一直在尝试使用RawDatagramSocket实现UDP客户端,但是遇到了困难。我既不能发送数据也不能接收数据。据我所知,这是Dart的一个比较新的特性,除了TCP之外,我找不到其他任何示例。
此外,我不知道是否存在错误或其他问题,但似乎我只能绑定到本地主机。当尝试绑定到另一台计算机的IPv4地址时,我会收到套接字异常(由于某些无效的IP地址而无法创建数据报套接字)。我已经尝试过使用tcp套接字,在Mac OS上运行dart代码,连接并向C#中实现的tcp服务器发送数据,没有任何问题。
有没有任何人在这方面有经验并且可以提供一个好的示例呢?
我的代码:
import 'dart:io';
import 'dart:convert';

void main() {
  var data = "Hello, World";
  var codec = new Utf8Codec();
  List<int> dataToSend = codec.encode(data);
  //var address = new InternetAddress('172.16.32.73');
  var address = new InternetAddress('127.0.0.1');
  RawDatagramSocket.bind(address, 16123).then((udpSocket) {
    udpSocket.listen((e) {
      print(e.toString());
      Datagram dg = udpSocket.receive();
      if(dg != null) 
        dg.data.forEach((x) => print(x));

    });
    udpSocket.send(dataToSend, new InternetAddress('172.16.32.73'), 16123);
    print('Did send data on the stream..');
  });
}

编辑

忙了几天后,我仔细阅读了API规范,并在下面的评论中得到了一些帮助,我了解到,由于它是一个一次性监听器,因此每次发送都必须将writeEventsEnabled设置为true。鉴于Günter、Fox32和Tomas的评论,其余更改非常简单。

我还没有测试将其设置为服务器,但我认为这只是绑定到首选端口(而不是像下面的示例中的0)的问题。服务器是在Windows 8.1上使用C#实现的,而Dart VM在Mac OS X上运行。

import 'dart:async';
import 'dart:io';
import 'dart:convert';

void connect(InternetAddress clientAddress, int port) {
  Future.wait([RawDatagramSocket.bind(InternetAddress.ANY_IP_V4, 0)]).then((values) {
    RawDatagramSocket udpSocket = values[0];
    udpSocket.listen((RawSocketEvent e) {
      print(e);
      switch(e) {
        case RawSocketEvent.READ :
          Datagram dg = udpSocket.receive();
          if(dg != null) {
            dg.data.forEach((x) => print(x));
          }
          udpSocket.writeEventsEnabled = true;
          break;
        case RawSocketEvent.WRITE : 
          udpSocket.send(new Utf8Codec().encode('Hello from client'), clientAddress, port);
          break;
        case RawSocketEvent.CLOSED : 
          print('Client disconnected.');
      }
    });
  });
}

void main() {
  print("Connecting to server..");
  var address = new InternetAddress('172.16.32.71');
  int port = 16123;
  connect(address, port);
}

绑定应该只对同一设备的IP地址起作用,对吗?据我所知,绑定应该设置发送者的IP地址。这不像连接到另一个IP那样,因为UDP没有“连接”的概念。 - Fox32
1
也许这些测试提供了一些信息 https://codereview.chromium.org/85993002/patch/230001/240014 - Günter Zöchbauer
我不知道,Fox32。我在源代码中查找了一下,似乎唯一获取流实例的方法是通过静态绑定方法。或者我有什么遗漏吗?我在Dart方面还是个新手。 - Joachim Birche
1
你尝试绑定到任何地址了吗?=> '0.0.0.0' - Fox32
2个回答

3

我不知道这是否是正确的做法,但它对我起作用了。

import 'dart:io';
import 'dart:convert';

void main() {
  var data = "Hello, World";
  var codec = new Utf8Codec();
  List<int> dataToSend = codec.encode(data);
  var addressesIListenFrom = InternetAddress.anyIPv4;
  int portIListenOn = 16123; //0 is random
  RawDatagramSocket.bind(addressesIListenFrom, portIListenOn)
    .then((RawDatagramSocket udpSocket) {
    udpSocket.forEach((RawSocketEvent event) {
      if(event == RawSocketEvent.read) {
        Datagram dg = udpSocket.receive();
        dg.data.forEach((x) => print(x));
      }
    });
    udpSocket.send(dataToSend, addressesIListenFrom, portIListenOn);
    print('Did send data on the stream..');
  });
}

1

这应该可以工作

import 'dart:io';
import 'dart:convert';

void main() {
  int port = 8082;

  // listen forever & send response
  RawDatagramSocket.bind(InternetAddress.anyIPv4, port).then((socket) {
    socket.listen((RawSocketEvent event) {
      if (event == RawSocketEvent.read) {
        Datagram dg = socket.receive();
        if (dg == null) return;
        final recvd = String.fromCharCodes(dg.data);

        /// send ack to anyone who sends ping
        if (recvd == "ping") socket.send(Utf8Codec().encode("ping ack"), dg.address, port);
        print("$recvd from ${dg.address.address}:${dg.port}");
      }
    });
  });
  print("udp listening on $port");

  // send single packet then close the socket
  RawDatagramSocket.bind(InternetAddress.anyIPv4, port).then((socket) {
    socket.send(Utf8Codec().encode("single send"), InternetAddress("192.168.1.19"), port);
    socket.listen((event) {
      if (event == RawSocketEvent.write) {
        socket.close();
        print("single closed");
      }
    });
  });

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接