Dart SocketMessage

Dart SocketMessage tutorial shows how to handle network communication in Dart using the SocketMessage class.

Dart SocketMessage

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.

main.dart

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.

main.dart

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.

main.dart

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.

main.dart

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.

main.dart

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

Dart Socket Documentation

This tutorial covered Dart’s SocketMessage patterns with practical examples showing text/binary formats, framing, JSON, and error handling for robust network communication.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Dart tutorials.

ad ad