Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send raw bytes through a Dart TCP socket

I'm stuck on the dumbest possible hindrance I can think of. I'm developing a flutter app that should send via TCP socket (on a local wifi network) an array of bytes.

Said bytes are raw and not representative of meaningful characters in any encoding (I have values like 0xFF and so on). My code succesfully connects and sends data by using the socket write method. Unfortunately that method only takes an encoded String as argument, and creating one from char codes botches up my message.

Here is my code:

var message = Uint8List(4);
var bytedata = ByteData.view(message.buffer);

bytedata.setUint8(0, 0x01);
bytedata.setUint8(1, 0x07);
bytedata.setUint8(2, 0xFF);
bytedata.setUint8(3, 0x88);

socket.write(String.fromCharCodes(message))

while 0x01 and 0x07 are received correctly, 0xFF and 0x88 get turned into a couple of other bytes, 0xC3BF and 0xC287 (checked with netcat -l 8080 | hexdump command).

I've googled for a while now for a way to send raw bytes without encoding them as strings, but couldn't find anything. Is it simply not contemplated? I realize Flutter and Dart are meant for high level web development, but it seems absurd to me.

like image 870
Maldus Avatar asked Oct 18 '18 07:10

Maldus


2 Answers

Obviously it is possible to write bytes without caring about encoding; Google searches however don't yield an immediate answer, probably because nobody else ever posed the question and the function itself has not a glaring name or description.

The Socket class in Dart inherits from the IOSink class, which has the add() method that does exactly what I need it to.

From the documentation:

void add (List<int> data) 

Adds byte data to the target consumer, ignoring encoding.
The encoding does not apply to this method, and the data list is passed directly to the target consumer as a stream event.
This function must not be called when a stream is currently being added using addStream.
This operation is non-blocking. See flush or done for how to get any errors generated by this call.

The data list should not be modified after it has been passed to add.

https://api.dartlang.org/stable/2.0.0/dart-io/Socket-class.html

The correct code is simply

var message = Uint8List(4);
var bytedata = ByteData.view(message.buffer);

bytedata.setUint8(0, 0x01);
bytedata.setUint8(1, 0x07);
bytedata.setUint8(2, 0xFF);
bytedata.setUint8(3, 0x88);

socket.add(message)
like image 188
Maldus Avatar answered Nov 14 '22 15:11

Maldus


Optimized solution

   import 'dart:typed_data';
    
    ///This class is useful to convert Hex String to ByteArray
    class Hex {
      ///Return [Uint8List] i.e byte array from the
      ///hex string. Hex string should be greter than or equal to
      ///2.
      static Uint8List toByteList(String hexString) {
        var message = Uint8List(hexString.length ~/ 2);
        var bytedata = ByteData.view(message.buffer);
        int counter = 0, i = 0;
        while (counter < hexString.length / 2) {
          String str = hexString.substring(i, i += 2);
          bytedata.setUint8(counter++, int.parse('0x$str'));
        }
        return message;
      }
    }

Use ::

Uint8List message = Hex.toByteList('0107FF88');
socket?.add(message);
like image 1
p_onefx Avatar answered Nov 14 '22 14:11

p_onefx