Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dart UDP client/server

I've been trying to implement a udp client by using the RawDatagramSocket but I'm kind of stuck. I can neither send or receive any data. It's a pretty new feature in Dart as far as I know and I can't find any examples except for tcp.

Also, I don't know if there is a bug or anything, but it seems like I can only bind to the localhost. When trying to bind to another computer IPV4 address, I receive a socket exception (failure to create datagram socket due to some invalid IP address). I've tried the tcp socket, connecting and sending data to a tcp server implemented in c# (while the dart code was running on Mac OS), without a problem.

Anyone who has worked on it and can provide a nice example?

My code:

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..');
  });
}

Edit

Been busy for a couple of days but after reading the API spec more thoroughly, and with some help from the comments below, I learned that, since it's a one-shot listener, the writeEventsEnabled must be set to true for every send. The rest of the changes are pretty straightforward given the comments by Günter, Fox32 and Tomas.

I haven't tested to set it up as a server yet but I assume that's just a matter of binding to the preferred port (instead of 0 as in the example below). The server was implemented in C# on a Windows 8.1, while the Dart VM was running on 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);
}
like image 486
Joachim Birche Avatar asked Jan 19 '14 20:01

Joachim Birche


2 Answers

I don't know if this is the right way to do it, but it got it working for me.

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..');
  });
}
like image 99
Thomas Pedersen Avatar answered Sep 21 '22 21:09

Thomas Pedersen


this should work

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");
      }
    });
  });

}
like image 24
Ali80 Avatar answered Sep 17 '22 21:09

Ali80