Dart SocketMessage
last modified April 4, 2025
The SocketMessage class in Dart provides a way to handle network
communication through sockets. It's useful for building client-server
applications and real-time systems.
SocketMessage manages message framing, serialization, and network transmission.
It's often used with Dart's dart:io library for socket programming.
Basic Definition
SocketMessage represents a discrete unit of communication over
sockets. It typically includes headers and a payload for structured data.
Key features include message framing, binary/string conversion, and error handling. It helps manage the complexity of network communication.
Basic SocketMessage Usage
This example shows basic message creation and sending through a socket.
import 'dart:io';
import 'dart:convert';
class SocketMessage {
final Map<String, String> headers;
final String body;
SocketMessage(this.headers, this.body);
List<int> toBytes() {
var headerStr = headers.entries
.map((e) => '${e.key}:${e.value}')
.join(';');
return utf8.encode('$headerStr|$body');
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4040);
print('Server listening on ${server.address}:${server.port}');
server.listen((client) {
client.transform(utf8.decoder).listen((data) {
print('Received: $data');
});
});
var client = await Socket.connect('127.0.0.1', 4040);
var message = SocketMessage(
{'type': 'greeting', 'length': '5'},
'Hello'
);
client.add(message.toBytes());
}
We create a simple SocketMessage class with headers and body. The server listens for connections while the client sends a formatted message. The message is converted to bytes for transmission.
$ dart main.dart Server listening on 127.0.0.1:4040 Received: type:greeting;length:5|Hello
Handling Binary Data
This example demonstrates working with binary data in SocketMessage.
import 'dart:io';
import 'dart:typed_data';
class BinarySocketMessage {
final int type;
final Uint8List data;
BinarySocketMessage(this.type, this.data);
Uint8List toBytes() {
var buffer = ByteData(4 + data.length);
buffer.setUint32(0, type);
buffer.buffer.asUint8List().setAll(4, data);
return buffer.buffer.asUint8List();
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((client) {
client.listen((data) {
var bytes = Uint8List.fromList(data);
var type = ByteData.sublistView(bytes, 0, 4).getUint32(0);
print('Received message type: $type');
});
});
var client = await Socket.connect('127.0.0.1', 4041);
var message = BinarySocketMessage(
42,
Uint8List.fromList([1, 2, 3, 4, 5])
);
client.add(message.toBytes());
}
We create a binary message format with a 4-byte type header followed by payload. The server extracts the message type from the binary data. This is efficient for binary protocols.
$ dart main.dart Received message type: 42
Message Framing
This example shows how to implement message framing with length prefixes.
import 'dart:io';
import 'dart:typed_data';
import 'dart:convert';
class FramedSocketMessage {
final String content;
FramedSocketMessage(this.content);
Uint8List toBytes() {
var contentBytes = utf8.encode(content);
var buffer = ByteData(4 + contentBytes.length);
buffer.setUint32(0, contentBytes.length);
buffer.buffer.asUint8List().setAll(4, contentBytes);
return buffer.buffer.asUint8List();
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4042);
server.listen((client) {
var buffer = <int>[];
client.listen((data) {
buffer.addAll(data);
if (buffer.length >= 4) {
var length = ByteData.sublistView(Uint8List.fromList(buffer), 0, 4)
.getUint32(0);
if (buffer.length >= 4 + length) {
var message = utf8.decode(buffer.sublist(4, 4 + length));
print('Framed message: $message');
buffer = buffer.sublist(4 + length);
}
}
});
});
var client = await Socket.connect('127.0.0.1', 4042);
var message = FramedSocketMessage('Hello, framed world!');
client.add(message.toBytes());
}
We implement length-prefixed message framing. The message starts with a 4-byte length followed by the payload. The server reads the length first then the exact payload bytes. This handles message boundaries correctly.
$ dart main.dart Framed message: Hello, framed world!
JSON Message Format
This example demonstrates using JSON for structured message content.
import 'dart:io';
import 'dart:convert';
class JsonSocketMessage {
final String type;
final Map<String, dynamic> payload;
JsonSocketMessage(this.type, this.payload);
List<int> toBytes() {
var message = {
'type': type,
'payload': payload,
'timestamp': DateTime.now().toIso8601String()
};
return utf8.encode(json.encode(message));
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4043);
server.listen((client) {
client.transform(utf8.decoder).listen((data) {
var message = json.decode(data);
print('${message['type']}: ${message['payload']}');
});
});
var client = await Socket.connect('127.0.0.1', 4043);
var message = JsonSocketMessage(
'user.login',
{'username': 'johndoe', 'password': 'secret'}
);
client.add(message.toBytes());
}
We create JSON-formatted messages with type and payload fields. The server decodes the JSON and extracts message components. This is useful for web APIs and structured communication.
$ dart main.dart
user.login: {username: johndoe, password: secret}
Error Handling
This example shows robust error handling in socket message processing.
import 'dart:io';
import 'dart:convert';
class SafeSocketMessage {
final String command;
final List<String> args;
SafeSocketMessage(this.command, this.args);
List<int> toBytes() {
try {
return utf8.encode('$command:${args.join(',')}');
} catch (e) {
return utf8.encode('error:Failed to encode message');
}
}
}
void main() async {
var server = await ServerSocket.bind('127.0.0.1', 4044);
server.listen((client) {
client.transform(utf8.decoder).listen(
(data) {
try {
var parts = data.split(':');
if (parts.length != 2) throw FormatException('Invalid format');
print('Command: ${parts[0]}, Args: ${parts[1].split(',')}');
} catch (e) {
print('Error processing message: $e');
client.write('error:Invalid message format');
}
},
onError: (e) => print('Connection error: $e'),
onDone: () => print('Client disconnected')
);
});
var client = await Socket.connect('127.0.0.1', 4044);
var message = SafeSocketMessage('calculate', ['add', '5', '3']);
client.add(message.toBytes());
client.listen((response) {
print('Server response: ${utf8.decode(response)}');
client.close();
});
}
We implement error handling at both message creation and processing stages. The client sends a structured command message while the server validates it. Error responses are sent back when problems occur.
$ dart main.dart Command: calculate, Args: [add, 5, 3] Client disconnected
Best Practices
- Message Framing: Always implement proper message boundaries
- Error Handling: Validate messages and handle errors gracefully
- Serialization: Choose appropriate formats (JSON, binary, etc.)
- Resource Management: Close sockets properly
- Timeouts: Implement timeouts for network operations
Source
This tutorial covered Dart's SocketMessage patterns with practical examples showing text/binary formats, framing, JSON, and error handling for robust network communication.
Author
List all Dart tutorials.