I have been trying to send image over socket connection from client to server which will be saved on the server.
The socket connection works fine for string messages but when I try to send an image, it is not transmitted correctly. Please give me a clue on what's the right way to do it.
Server-side code:
import 'dart:io';
import 'dart:typed_data';
void main() async {
Uint8List bytes= await File('1.jpg').readAsBytes();
final socket = await Socket.connect('localhost', 8000);
print('Connected to: ${socket.remoteAddress.address}:${socket.remotePort}');
// listen for responses from the server
socket.listen(
// handle data from the server
(Uint8List data) {
final serverResponse = String.fromCharCodes(data);
print('Server: $serverResponse');
},
// handle errors
onError: (error) {
print(error);
socket.destroy();
},
// handle server ending connection
onDone: () {
print('Server left.');
socket.destroy();
},
);
// send some messages to the server
await sendMessage(socket, bytes);
}
Future<void> sendMessage(Socket socket, Uint8List message) async {
print('Client: $message');
socket.write(message);
}
Client-side code:
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:image/image.dart';
void main() async {
// bind the socket server to an address and port
final server = await ServerSocket.bind('127.0.0.1', 8000);
// listen for clent connections to the server
server.listen((client) {
handleConnection(client);
});
}
void handleConnection(Socket client) {
print('Connection from'
' ${client.remoteAddress.address}:${client.remotePort}');
// listen for events from the client
client.listen(
// handle data from the client
(Uint8List data) async {
// final message = String.fromCharCodes(data);
print(data);
await File('new.jpg').writeAsBytes(data);
},
// handle errors
onError: (error) {
print(error);
client.close();
},
// handle the client closing the connection
onDone: () {
print('Client left');
client.close();
},
);
}
Faulty image on server-side:
Just change socket.write(message) to socket.add(message) at the client-side and you are good to go
Future<void> sendMessage(Socket socket, Uint8List message) async {
print('Client: $message');
socket.add(message);
}
because socket.write(object) Converts object to a String by invoking Object.toString.
have a nice day:)
Related
If you run this in DartPad you'll never catch the exceptions, they are reported as unhandled in the console. Why?
import 'dart:html';
void main() async {
try {
final socket = await wsConnect('wss://127.0.0.1:7654');
print('${socket.readyState}');
} catch (e) {print(e);}
}
Future<WebSocket> wsConnect(String url) async {
final socket = WebSocket(url);
socket.onError.listen((_) => throw Exception('connection error'));
socket.onClose.listen((_) => throw Exception('connection close'));
return socket;
}
This doesn't work either:
import 'dart:html';
void main() async {
try {
final socket = await wsConnect('wss://127.0.0.1:7654', () => throw Exception('some problem'));
print('${socket.readyState}');
} catch (e) {print(e);}
}
Future<WebSocket> wsConnect(String url, void Function() onProblem) async {
final socket = WebSocket(url);
socket.onError.listen((_) => onProblem());
socket.onClose.listen((_) => onProblem());
return socket;
}
Are the stream callbacks being executed on some separate zone, isolate or VM or whatnot and where can I read about it?
A server that will keep a permanent connection via Tcp. And close when the program is shut down.
An example of connecting a server that reconnects every time:
class Server {
void connectToServer() async {
try {
Socket _socket = await Socket.connect('127.0.0.1', 7890);
log('connected: ${_socket.address}:${_socket.port}');
} catch (e) {
log(e.toString());
}
}
void send(temp) async {
Socket _socket = await Socket.connect('127.0.0.1', 7890);
_socket.listen((List<int> event) {
log(utf8.decode(event));
});
_socket.add(utf8.encode(temp));
}
}
I'm implementing socket.
Two clients connect to the server with no problem, when client1 sends a message to the server, the server publishes it to every other client (which in this case is client2). but client2 won't get the message unless it sends a message. It seems the listener of the client doesn't work. Obviously, I want client2 to get the message from client1 instantly.
here is my sever code:
import 'dart:io';
import 'dart:typed_data';
void main() async {
// bind the socket server to an address and port
MySocket mySocket = MySocket();
await mySocket.init();
}
class MySocket {
ServerSocket? server;
List<Socket> clients = [];
//initialize the socket
init() async {
server = await ServerSocket.bind("192.168.0.112", 4000);
// listen for client connections to the server
server!.listen((client) {
handleConnection(client);
addClient(client);
});
}
void handleConnection(Socket client) async {
print('Connection from'
' ${client.remoteAddress.address}:${client.remotePort}');
// listen for events from the client
client.listen(
// handle data from the client
(Uint8List data) async {
await Future.delayed(Duration(seconds: 1));
final message = String.fromCharCodes(data);
print(message);
publish(message, client);
},
// handle errors
onError: (error) {
print(error);
client.close();
},
// handle the client closing the connection
onDone: () {
print('Client left');
client.close();
},
);
}
void addClient(Socket client) {
//if client doesn't already exist add it to the list of clients
if (!clients.any((element) =>
'${client.remoteAddress.address}:${client.remotePort}' ==
'${element.remoteAddress.address}:${element.remotePort}')) {
clients.add(client);
}
}
void publish(String message, Socket client) {
//write the message to every client except the author of it
clients.forEach((element) async {
if ('${client.remoteAddress.address}:${client.remotePort}' !=
'${element.remoteAddress.address}:${element.remotePort}') {
element.write(message);
}
});
}
}
here is my client-side code:
import 'dart:io';
import 'dart:typed_data';
void main() async {
//gets the username
String name = '';
while (name.isEmpty) {
print('Enter your name: ');
name = stdin.readLineSync() ?? '';
}
// connect to the socket server
final socket = await Socket.connect("192.168.0.112", 4000);
print('Connected to: ${socket.remoteAddress.address}:${socket.remotePort}');
// listen for responses from the server
socket.listen(
// handle data from the server
(Uint8List data) {
final serverResponse = String.fromCharCodes(data);
print('$serverResponse');
},
// handle errors
onError: (error) {
print(error);
socket.destroy();
},
// handle server ending connection
onDone: () {
print('Left server.');
socket.destroy();
},
);
// sending messages to the server
String message = "";
while (message != "exit") {
message = stdin.readLineSync() ?? '';
await sendMessage(socket, name, message);
}
socket.close();
}
Future<void> sendMessage(Socket socket, String name, String message) async {
socket.write('$name: $message');
await Future.delayed(Duration(seconds: 2));
}
Thank you in advance.
The issue is because stdin.readLineSync() in your client blocks the current thread. You can get around this by spawning an isolate to handle that portion of the code, so that it does not block the socket.listen from printing out the responses from the server.
See updated client code below:
import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data';
void main() async {
//gets the username
String name = '';
while (name.isEmpty) {
print('Enter your name: ');
name = stdin.readLineSync() ?? '';
}
// connect to the socket server
final socket = await Socket.connect("192.168.0.112", 4000);
print('Connected to: ${socket.remoteAddress.address}:${socket.remotePort}');
// listen for responses from the server
socket.listen(
// handle data from the server
(Uint8List data) {
final serverResponse = String.fromCharCodes(data);
print('$serverResponse');
},
// handle errors
onError: (dynamic error) {
print(error);
socket.destroy();
},
// handle server ending connection
onDone: () {
print('Left server.');
socket.destroy();
},
);
final receive = ReceivePort();
final isolate = await Isolate.spawn(readMessages, receive.sendPort);
await for (final message in receive) {
if (message == 'exit') break;
await sendMessage(socket, name, message as String);
}
socket.close();
}
void readMessages(SendPort port) {
String message = '';
while (message != 'exit') {
message = stdin.readLineSync() ?? '';
port.send(message);
}
Isolate.exit(port);
}
Future<void> sendMessage(Socket socket, String name, String message) async {
socket.write('$name: $message');
await Future<void>.delayed(Duration(seconds: 2));
}
I am trying to control dart script via socket, running within isolate
I came up with some (spoiler warning) not working code:
import "dart:io";
import "dart:convert";
import "dart:isolate";
reader(SendPort sendPort) async {
var serverSocket = await ServerSocket.bind("127.0.0.1", 83);
print('connected');
await for (var socket in serverSocket) {
socket.transform(UTF8.decoder).listen((msg) => sendPort.send(msg));
}
}
main() {
bool start = false;
bool stop = false;
listener (message)
{
print ("message from isolate: $message");
stop = start;
start = true;
}
ReceivePort receive = new ReceivePort();
receive.listen(listener);
Isolate.spawn(reader, receive.sendPort).then((Isolate) => print("Isolate started"));
print("Waiting to start");
while (!start) {}
print("Waiting to stop");
while (!stop) {}
print("Ended");
}
But isolate does not even seem to be launched. Only output of script is "Waiting to start"
This worked for me:
import 'dart:async';
import "dart:io";
import "dart:convert";
import "dart:isolate";
reader(SendPort sendPort) async {
print('isolate started');
var serverSocket = await ServerSocket.bind("127.0.0.1", 8123);
sendPort.send('bound');
await for (var socket in serverSocket) {
socket.transform(UTF8.decoder).listen((msg) {
print('server received $msg');
sendPort.send(msg);
if (msg == 'close') {
socket.close();
serverSocket.close();
}
});
}
}
StreamSubscription subscription;
Isolate isolate;
ReceivePort receive;
main() async {
listener(message) async {
print("message from isolate: $message");
if (message == 'bound') {
final socket = await Socket.connect("127.0.0.1", 8123);
print('client connected');
socket.add('close'.codeUnits);
socket.destroy();
}
if (message == 'close') {
subscription.cancel();
// exits application
}
}
receive = new ReceivePort();
subscription = receive.listen(listener);
isolate = await Isolate.spawn(reader, receive.sendPort);
}
I'm using Dart 1.8.5 on server.
I want to implement TCP Socket Server that listens to incoming connections, sends some data to every client and stops to generate data when client disconnects.
Here is the sample code
void main() {
ServerSocket.bind(
InternetAddress.ANY_IP_V4,
9000).then((ServerSocket server) {
runZoned(() {
server.listen(handleClient);
}, onError: (e) {
print('Server error: $e');
});
});
}
void handleClient(Socket client) {
client.done.then((_) {
print('Stop sending');
});
print('Send data');
}
This code accepts connections and prints "Send data". But it will never print "Stop sending" even if client was gone.
The question is: how to catch client disconnect in listener?
A Socket is bidirectional, i.e. it has an input stream and an output sink. The Future returned by done is called when the output sink is closed by calling Socket.close().
If you want to be notified when the input stream closes try using Socket.drain() instead.
See the example below. You can test it with telnet. When you connect to the server it will send the string "Send." every second. When you close telnet (ctrl-], and then type close). The server will print "Stop.".
import 'dart:io';
import 'dart:async';
void handleClient(Socket socket) {
// Send a string to the client every second.
var timer = new Timer.periodic(
new Duration(seconds: 1),
(_) => socket.writeln('Send.'));
// Wait for the client to disconnect, stop the timer, and close the
// output sink of the socket.
socket.drain().then((_) {
print('Stop.');
timer.cancel();
socket.close();
});
}
void main() {
ServerSocket.bind(
InternetAddress.ANY_IP_V4,
9000).then((ServerSocket server) {
runZoned(() {
server.listen(handleClient);
}, onError: (e) {
print('Server error: $e');
});
});
}