Flutter/Dart: Parse the results of Ping Function - flutter

So I am using this function that utilizes the dart_ping.dart package
and I would like to only extract the ip, ttl and time from the result this function is giving.
void ping(String site) async {
// Create ping object with desired args
final ping = Ping(site, count: 5);
print('Running command: ${ping.command}');
// Begin ping process and listen for output
ping.stream.listen((PingData event) {
setState(() {
ping1 = event;
});
pingsArray.add(event);
print(event.summary);
});
}

you have to extract them from the PingData so in below code I will show you how to get the values. the ip, ttl, time from the response are assigned to the varialbles ip, ttl, time. You can probably start from there. Since I do not exactly know what you want to achieve, this is probably all I can show you.
void _ping(String site) async {
// Create ping object with desired args
final ping = Ping(site, count: 5);
print('Running command: ${ping.command}');
// Begin ping process and listen for output
ping.stream.listen((PingData event) {
final res = event.response;
if (res == null) return;
final ip = res.ip;
final ttl = res.ttl;
final time = res.time;
});
}
Thank you.

Related

is there have a concurrent List in flutter

When I add some elements in HashMap in flutter like this:
void loadingMoreChannel(RefreshController _refreshController) async {
articleRequest.pageNum = articleRequest.pageNum + 1;
List<Channel> channels = await Repo.getChannels(articleRequest);
channels.addAll(channels);
_refreshController.loadComplete();
}
first step fetched some channel information from the server side, then add the channel info into List, shows error:
Concurrent modification during iteration: Instance(length:15) of '_GrowableList'.<…>
what should I do to add the channel elements into list concurrent?
Seems you need to rename the variable. You can just do
void loadingMoreChannel(RefreshController _refreshController) async {
articleRequest.pageNum = articleRequest.pageNum + 1;
List<Channel> result = await Repo.getChannels(articleRequest);
channels.addAll(result); //it was having same name
_refreshController.loadComplete();
}

How to break up Dart Isolate code to avoid blocking the event queue?

I am writing a test program to explore the use of Isolates in Dart/Flutter. One type of isolate that I have is started and stopped using a switch on a Flutter UI. This sends a message (START and STOP) to the isolate and I use a ValueNotifier to detect these commands and respond to them. When I initially wrote this, the Isolate ran continuously and didn’t respond the to the STOP command, which I understand is because the event queue would never be empty to process it.
Based on the first answer to this thread...
How to terminate a long running isolate #2
… and the suggested approach on this blog page:
https://hackernoon.com/executing-heavy-tasks-without-blocking-the-main-thread-on-flutter-6mx31lh
… I have tried to break my code up using Futures. I have split my run block into runWorker() and runChunk() functions, with runChunk called repeatedly as long as the Isolate should be running (run == true). I am doing something wrong because the Isolate still runs away and does not process the STOP command. I get slightly different results depending on whether I call runChunk directly or using Future.delayed (as per the hackernoon blog page), but neither approach works.
I believe that the STOP code works because if I remove the processing loop then everything triggers as expected, and I had an earlier version of this that worked when I included a 'Future.delayed' of 1 microsecond between each counter loop. So assume I am just using Futures incorrectly and not freeing up the event queue between 'runChunk' calls.
Can anyone tell me what I am doing wrong here? Here is the code for my isolate...
import 'dart:async';
import 'dart:isolate';
import 'package:flutter/material.dart';
class ContinuousIsolator {
ContinuousIsolator(
{required int channel, required void Function(double) setCounter}) {
print('Isolator initialisation');
_channel = channel;
_setCounter = setCounter;
spawn();
}
late int _channel; // The id of this isolate
late void Function(double) _setCounter;
late SendPort _port;
late Isolate _isolate;
ReceivePort receivePort = ReceivePort();
// Spawn a new isolate to complete the countdown (or up)
// channel = the number of the isolate
// counter = the value to count down from (or up to)
void spawn() {
print('Isolator establishing receiver');
receivePort.listen((msg) {
// print('Isolator message received');
// Unpack the map from the returned string
Map<int, dynamic> map = Map<int, dynamic>.from(msg);
// There should be only one key:value pair
for (var key in map.keys) {
msg = map[key]; // Extract the message
}
// print('Channel $_channel received "$msg" of type ${msg.runtimeType}');
// If we have received a Sendport, then add it to the port map
if (msg is SendPort) {
_port = msg;
} else {
// Otherwise process the message
// If it contains 'END' then we need to terminate the isolate
switch (msg) {
case 'END':
_isolate.kill();
// Isolate has completed, then close this receiver port
receivePort.close();
break;
default:
_setCounter(msg); // Send message to display
break;
}
}
});
// Start the isolate then let's get working on the countdown timer
Isolate.spawn(worker, {_channel: receivePort.sendPort}).then((isolate) {
_isolate = isolate; // Capture isolate so we can kill it later
});
}
void run() {
print('Sending START to worker');
_port.send('START');
}
void stop() {
print('Sending STOP to worker');
_port.send('STOP');
}
void end() {
_port.send('END'); // Send counter value to start countdown
}
}
void worker(Map<int, dynamic> args) {
int? id; // Number for this channel
ReceivePort receivePort = ReceivePort(); // Receive port for
SendPort? sendPort;
ValueNotifier<String> message = ValueNotifier('');
const double start = 10000000;
double counter = start;
const int chunkSize = 1000;
bool down = true;
bool run = true;
// Unpack the args to get the id and sendPort.
// There should be only one key:value pair
dynamic msg = '';
Map<int, dynamic> map = Map<int, dynamic>.from(args);
for (var key in map.keys) {
id = key; // Extract the isolate id
msg = map[key]; // Extract the message
}
// First message should contain the receivePort for the main isolate
if (msg is SendPort) {
sendPort = msg;
// print('args: $args port: $sendPort');
print('worker $id sending send port');
sendPort.send({id: receivePort.sendPort});
}
double getCounter() {
return counter;
}
void setCounter(double value) {
counter = value;
}
bool getDown() {
return down;
}
void setDown(bool value) {
down = value;
}
Future runChunk(
int chunkSize,
bool Function() getDown,
void Function(bool) setDown,
double Function() getCounter,
void Function(double) setCounter) {
const double start = 10000000;
print('Running chunk, counter is ${getCounter()}');
for (int i = 0; i < chunkSize; i++) {
// print('Worker $id in the while loop');
if (getDown() == true) {
setCounter(getCounter() - 1);
if (getCounter() < 0) setDown(!getDown());
} else {
setCounter(getCounter() + 1);
if (getCounter() > start) setDown(!getDown());
}
if ((getCounter() ~/ 1000) == getCounter() / 1000) {
// print('Continuous Counter is ${getCounter()}');
sendPort!.send({id: getCounter()});
} // Send the receive port
}
return Future.value();
}
void changeMessage() {
print('Message has changed to ${message.value}');
if (message.value == 'START') {
run = true;
} else {
run = false;
}
}
void runWorker() async {
message.addListener(changeMessage);
print('Worker running counter down from $counter');
while (run == true) {
// This line appears to run the isolate, but there is no output/feedback to the GUI
// The STOP command does not interrupt operation.
Future.delayed(const Duration(microseconds: 0),
() => runChunk(chunkSize, getDown, setDown, getCounter, setCounter));
// This line runs the isolate with feedback to the GUI
// The STOP command does not interrupt operation.
runChunk(chunkSize, getDown, setDown, getCounter, setCounter);
}
message.removeListener(changeMessage);
}
// Establish listener for messages from the controller
print('worker $id establishing listener');
receivePort.listen((msg) {
print('worker $id has received $msg');
switch (msg) {
case 'START':
print('Worker $id starting run');
message.value = msg;
runWorker();
break;
case 'STOP':
print('Worker $id stopping run');
message.value = msg;
break;
case 'END':
message.removeListener(changeMessage);
receivePort.close;
break;
default:
break;
}
});
}
Ok, so it turns out that the problem was not with the Futures, but with this line of code in the runWorker() method:
while (run == true) {
... which (I think) was blocking the event queue.
I also think I was over-thinking things using a ValueNotifier (although I don't think there is any reason why this wouldn’t work).
I have simplified my code so that the main computation method (runChunk) checks if it should still be running after each chunk, and if the answer is yes then it just calls itself again to run the next chunk.
The run flag is set to true and runChunk called when START is received from the parent and the run flag is set to false when STOP is received. This removes the need for the ValueNotifier.
Everything works as expected now and the isolate computation (‘runChunk’) can be started and stopped on demand.
Here is the revised code (the print lines are debug lines that I have left in):
import 'dart:async';
import 'dart:isolate';
class ContinuousIsolator {
ContinuousIsolator(
{required int channel, required void Function(double) setCounter}) {
print('Isolator initialisation');
_channel = channel;
_setCounter = setCounter;
spawn();
}
late int _channel; // The id of this isolate
late void Function(double)
_setCounter; // Callback function to set on-screen counter
late SendPort _port; // SendPort of child isolate to communicate with
late Isolate _isolate; // Pointer to child isolate
ReceivePort receivePort = ReceivePort(); // RecevierPort for this class
// Spawn a new isolate to complete the countdown (or up)
// channel = the number of the isolate
// counter = the value to count down from (or up to)
void spawn() {
print('Isolator establishing receiver');
// Establish a listener for messages from the child
receivePort.listen((msg) {
// Unpack the map from the returned string (child sends a single map
// contained key: isolate id and value: message)
Map<int, dynamic> map = Map<int, dynamic>.from(msg);
// There should be only one key:value pair received
for (var key in map.keys) {
msg = map[key]; // Extract the message
}
// If we have received a Sendport, then capture it to communicate with
if (msg is SendPort) {
_port = msg;
} else {
// Otherwise process the message
// If it contains 'END' then we need to terminate the isolate
switch (msg) {
case 'END':
_isolate.kill();
// Isolate has completed, then close this receiver port
receivePort.close();
break;
default:
_setCounter(msg); // Send message to display
break;
}
}
});
// Start the child isolate
Isolate.spawn(worker, {_channel: receivePort.sendPort}).then((isolate) {
_isolate = isolate; // Capture isolate so we can kill it later
});
}
// Class method to start the child isolate doing work (countdown timer)
void run() {
print('Sending START to worker');
_port.send('START');
}
// Class method to stop the child isolate doing work (countdown timer)
void stop() {
print('Sending STOP to worker');
_port.send('STOP');
}
// Class method to tell the child isolate to self-terminate
void end() {
_port.send('END'); // Send counter value to start countdown
}
}
// Child isolate function that is spawned by the parent class ContinuousIsolator
// Called initially with single map of key: 'unique channel id' and value:
// receiver port from the parent
void worker(Map<int, dynamic> args) {
int? id; // Unique id number for this channel
ReceivePort receivePort = ReceivePort(); // Receive port for this isolate
SendPort? sendPort; // Send port to communicate with the parent
const double start = 10000000; // Starting counter value
double counter = start; // The counter
const int chunkSize =
100; // The number of counter decrements/increments to process per 'chunk'
bool down = true; // Flag to show is counting 'down' (true) or 'up' (false)
bool run = false; // Flag to show if the isolate is running the computation
// Unpack the initial args to get the id and sendPort.
// There should be only one key:value pair
dynamic msg = '';
Map<int, dynamic> map = Map<int, dynamic>.from(args);
for (var key in map.keys) {
id = key; // Extract the isolate id
msg = map[key]; // Extract the message
}
// The first message should contain the receivePort for the main isolate
if (msg is SendPort) {
sendPort = msg; // Capture sendport to communicate with the parent
print('worker $id sending send port');
// Send the receiver port for this isolate to the parent
sendPort.send({id: receivePort.sendPort});
}
// Method to get the current counter value
double getCounter() {
return counter;
}
// Method to set the current counter value
void setCounter(double value) {
counter = value;
}
// Method to get the down flag value
bool getDown() {
return down;
}
// Method to set the down flag value
void setDown(bool value) {
down = value;
}
// This function does the main work of the isolate, ie the computation
Future<void> runChunk(
int chunkSize, // The number of loops to process for a given 'chunk'
bool Function() getDown, // Callback to get bool down value
void Function(bool) setDown, // Callback to set bool down value
double Function() getCounter, // Call back to get current counter value
void Function(double) setCounter) // Callback to set counter value
async {
const double start = 10000000; // Starting value for the counter
// Count down (or up) the counter for chunkSize iterations
for (int i = 0; i < chunkSize; i++) {
// Counting down...
if (getDown() == true) {
setCounter(getCounter() - 1);
// If reached zero, flip the counting up
if (getCounter() < 0) setDown(!getDown());
} else {
// Counting up...
setCounter(getCounter() + 1);
// If reached start (max), flip the counting down
if (getCounter() > start) setDown(!getDown());
}
// Update the display every 1000 points
if ((getCounter() ~/ 1000) == getCounter() / 1000) {
sendPort!.send({id: getCounter()}); // Notify parent of the new value
}
}
// If the isolate is still running (parent hasn't sent 'STOP') then
// call this function again to iterate another chunk. This gives the event
// queue a chance to process the 'STOP'command from the parent
if (run == true) {
// I assume Future.delayed adds call back onto the event queue
Future.delayed(const Duration(microseconds: 0), () {
runChunk(chunkSize, getDown, setDown, getCounter, setCounter);
});
}
}
// Establish listener for messages from the controller
print('worker $id establishing listener');
receivePort.listen((msg) {
print('worker $id has received $msg');
switch (msg) {
case 'START':
// Start the worker function running and set run = true
print('Worker $id starting run');
run = true;
runChunk(chunkSize, getDown, setDown, getCounter, setCounter);
break;
case 'STOP':
// Set run = false to stop the worker function
print('Worker $id stopping run');
run = false;
break;
case 'END':
// Inform parent that isolate is shutting down
sendPort?.send({id: msg});
receivePort.close; // Close the receiver port
break;
default:
break;
}
});
}

Udp socket in Flutter does not receive anything

I'm trying to use a udp socket as server in Flutter. I'd like to bind this socket on my localhost at 6868 port always in listening. Unfortunately when i try to send something from a client,it never prints the string "RECEIVED".
Here's the code:
static Future openPortUdp(Share share) async {
await RawDatagramSocket.bind(InternetAddress.anyIPv4,6868)
.then(
(RawDatagramSocket udpSocket) {
udpSocket.listen((e) {
switch (e) {
case RawSocketEvent.read:
print("RECEIVED");
print(String.fromCharCodes(udpSocket.receive().data));
break;
case RawSocketEvent.readClosed:
print("READCLOSED");
break;
case RawSocketEvent.closed:
print("CLOSED");
break;
}
});
},
);
}
Am I doing something wrong?
Anyway this is the client side, it is written is Lua:
local udp1 = socket.udp()
while true do
udp1:setpeername("192.168.1.24", 6868)
udp1:send("HI")
local data1 = udp1:receive()
if (not data1 == nil) then print(data1) break end
udp1:close()
end
I tested it with another server and it works well, so i don't think the client is the problem.
Thanks!
If it can help you, here my code for my SocketUDP (as singleton) in my app.
I used it in localhost and it works very well :
class SocketUDP {
RawDatagramSocket _socket;
// the port used by this socket
int _port;
// emit event when receive a new request. Emit the request
StreamController<Request> _onRequestReceivedCtrl = StreamController<Request>.broadcast();
// to give access of the Stream to listen when new request is received
Stream<Request> get onRequestReceived => _onRequestReceivedCtrl.stream;
// as singleton to maintain the connexion during the app life and be accessible everywhere
static final SocketUDP _instance = SocketUDP._internal();
factory SocketUDP() {
return _instance;
}
SocketUDP._internal();
void startSocket(int port) {
_port = port;
RawDatagramSocket.bind(InternetAddress.anyIPv4, _port)
.then((RawDatagramSocket socket) {
_socket = socket;
// listen the request from server
_socket.listen((e) {
Datagram dg = _socket.receive();
if (dg != null) {
_onRequestReceivedCtrl.add(RequestConvert.decodeRequest(dg.data, dg.address));
}
});
});
}
void send(Request requestToSend, {bool isBroadCast:false}) {
_socket.broadcastEnabled = isBroadCast;
final String requestEncoded = RequestConvert.encodeRequest(requestToSend);
List<int> requestAsUTF8 = utf8.encode(requestEncoded);
_socket.send(requestAsUTF8, requestToSend.address, _port);
}
}

Handling callbacks in Dart classes

My dart application it's listening to a socket I want to return the socket reply on the command(...) function after it is processed in the dataHandler event.
import 'dart:io';
import 'dart:async';
class TeamSpeak3{
Socket socket;
String command;
String _ip;
int _port;
TeamSpeak3(String ip, int port) {
this._ip = ip;
this._port = port;
}
Future<int> connect() async {
await Socket.connect(_ip, _port)
.then((Socket sock) {
socket = sock;
socket.listen(
dataHandler,
onError: errorHandler,
onDone: doneHandler,
cancelOnError: false);
}).catchError((AsyncError e) {
print("Connection failed: $e");
exit(1);
});
socket.done;
return 1;
}
void auth(String name, String pass){
socket.write("login $name $pass\n");
}
void send(String cmd){
command = cmd;
socket.write('$cmd\n');
//return reply from dataHandler
}
void dataHandler(data){
var reply = new String.fromCharCodes(data).trim();
//return $reply on the send function
}
void errorHandler(error, StackTrace trace){
print(error);
}
void doneHandler(){
print("Connection termiated!");
socket.destroy();
exit(0);
}
}
First of all, you don't know for sure that the entire response to your send arrives in one packet, so you might not have the entire response.
Let's assume that you do (otherwise you'll have to do more processing in dataHandler to collect the response before delivering it).
The canonical way to allow a callback to be called when something has happened in the future, is to return a Future. You will also need a way to complete that future, so you create a Completer and store it until you need it. Since you can probably do more sends, you need to remember more than one completer. So, all in all, I'd write this as:
Queue<Completer<String>> _queue = Queue();
Future<String> send(String cmd){
socket.writeln(cmd);
var completer = new Completer<String>();
_queue.add(completer);
return completer.future;
}
void _dataHandler(data){
var reply = new String.fromCharCodes(data).trim();
// Add some sanity checking here. Make sure you have the entire response before
// executing the code below.
_queue.removeFirst().complete(reply);
}
(I made _dataHandler private because you probably don't want the user calling send to alse be able to call dataHandler).

Xamarin Forms Sockets

I don't get it, my friend and I are developing an API and our WebSocket services works, but not the mobile side.. I tried with a couple of clients, on the web, our echo messaging and everything works.
The thing is, I mean, the things seem like the socket is mono-directional. I tried the example of https://github.com/rdavisau/sockets-for-pcl#a-tcp-client:
var address = "127.0.0.1";
var port = 11000;
var r = new Random();
var client = new TcpSocketClient();
await client.ConnectAsync(address, port);
// we're connected!
for (int i = 0; i<5; i++)
{
// write to the 'WriteStream' property of the socket client to send data
var nextByte = (byte) r.Next(0,254);
client.WriteStream.WriteByte(nextByte);
await client.WriteStream.FlushAsync();
// wait a little before sending the next bit of data
await Task.Delay(TimeSpan.FromMilliseconds(500));
}
await client.DisconnectAsync();
First, after I get connected with this :
public async void ConnectSocketToAPIAsync()
{
SocketClient = new TcpSocketClient();
await SocketClient.ConnectAsync("my.ws.service", 4242);
ActiveSocketExchange();
}
public async void ActiveSocketExchange()
{
var bytesRead = -1;
var buf = new byte[1];
while (bytesRead != 0)
{
bytesRead = await SocketClient.ReadStream.ReadAsync(buf, 0, 1);
if (bytesRead > 0)
MessagingCenter.Send((App)Current, SOCKET_Message, System.Text.Encoding.UTF8.GetString(buf, 0, bytesRead));
}
}
Everything's fine, my TcpClient is well initialized (even the web-link becomes the http's API addr)
From my page view, when I'm done writing my text, I'm pressing the done button of the keyboard and this code is called:
private void InitSocketPart()
{
MessagingCenter.Subscribe<App, string>((App)Application.Current, App.SOCKET_Message, (sender, text) =>
{
SocketResponseText = text;
});
}
private async void OnTextCompleted(object sender, EventArgs ea)
{
var bytes = Encoding.UTF8.GetBytes(TextToSend);
try {
if (App.SocketClient.WriteStream.CanRead)
Debug.WriteLine("canRead");
if (App.SocketClient.WriteStream.CanWrite)
Debug.WriteLine("canWrite");
App.SocketClient.WriteStream.Write(bytes, 0, TextToSend.Length);
App.SocketClient.WriteStream.Flush();
} catch (Exception e)
{
Debug.WriteLine(e);
}
}
So now CanWrite && CanRead are true, but nothing at all happens, even with the use of Async methods... Why so? I don't get it..
The use of messaging center is just to have only one point of incoming message. I'm using it for other things and it works perfectly :)
Thank for any help..