binstruct 0.2.5
binstruct: ^0.2.5 copied to clipboard
A binary struct parser/builder similar to Python's construct
example/main.dart
import 'dart:io';
import 'package:binstruct/binstruct.dart';
// This example demonstrates simple UDP server-client communication using the
// BinStruct library to define a binary protocol.
// The server listens for requests, processes them, and sends back responses.
// The client sends requests with a payload and waits for the server's response.
// The protocol uses a fixed-size packet structure with a header and payload.
// The header contains version and type fields, while the payload is a 16-bit signed integer.
// To run this example:
// 1. Start the server: `dart main.dart server`
// 2. In another terminal, run the client with a payload: `dart main.dart client 42`
// 3. The server will respond with the payload doubled, or 0 if the doubled payload is out of range.
enum PacketVersion { v1 }
enum PacketType { request, response }
final BinStruct packetStruct = BinStruct([
BitStruct('header', [
BitField('version', 2),
BitField('type', 2),
BitField('unused', 4),
]),
Int16('payload')
]);
const int port = 12345;
const String serverAddress = '127.0.0.1';
Future<void> runServer() async {
final server = await RawDatagramSocket.bind(InternetAddress.anyIPv4, port);
print('Server listening on ${server.address.address}:$port');
server.listen((event) {
if (event == RawSocketEvent.read) {
final datagram = server.receive();
if (datagram != null) {
final packet = packetStruct.parse(datagram.data);
print('Server received: ${packet['payload']}');
if (packet['header']['version'] != PacketVersion.v1.index ||
packet['header']['type'] != PacketType.request.index) {
return;
}
int response = packet['payload'] * 2;
if (response < -32768 || response > 32767) {
response = 0;
}
// Prepare response
final responsePacket = packetStruct.build({
'header': {
'version': PacketVersion.v1.index,
'type': PacketType.response.index,
'unused': 0,
},
'payload': response
});
server.send(responsePacket, datagram.address, datagram.port);
print('Server sent response: ${response}');
}
}
});
print('Server is running. Press Ctrl+C to stop.');
await Future.delayed(Duration(hours: 1)); // Keep the server running for 1 hour
server.close();
print('Server stopped.');
}
Future<void> runClient(int payload) async {
final socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0);
print('Client sending from ${socket.address.address}:${socket.port}');
final packet = packetStruct.build({
'header': {
'version': PacketVersion.v1.index,
'type': PacketType.request.index,
'unused': 0,
},
'payload': payload
});
socket.send(packet, InternetAddress(serverAddress), port);
print('Client sent packet with payload: $payload');
socket.listen((event) {
if (event == RawSocketEvent.read) {
final datagram = socket.receive();
if (datagram != null) {
final response = packetStruct.parse(datagram.data);
if (response['header']['version'] != PacketVersion.v1.index ||
response['header']['type'] != PacketType.response.index) {
print('Invalid response from server');
return;
}
print('Client received: ${response['payload']}');
socket.close();
}
}
});
}
void main(List<String> args) async {
if (args.isEmpty) {
print('Usage: dart main.dart [server|client]');
exit(1);
}
if (args[0] == 'server') {
await runServer();
} else if (args[0] == 'client') {
if (args.length < 2) {
print('Usage: dart main.dart client [param]');
exit(1);
}
await runClient(int.parse(args[1]));
} else {
print('Invalid option: ${args[0]}');
exit(1);
}
}