native_socket 0.4.1
native_socket: ^0.4.1 copied to clipboard
Use unix sockets via file descriptors.
Native Socket #
Low-level Unix domain socket operations with a high-level Dart API.
Provides stream and datagram Unix domain sockets, filesystem-path and abstract namespace addressing, SCM_RIGHTS file descriptor passing, server sockets, native (off-heap) buffers, concurrent read/write via split halves, and prebuilt release assets for Linux and Android.
macOS is supported via source fallback.
Features #
- Stream sockets (
SOCK_STREAM) — connection-oriented, ordered, reliable - Datagram sockets (
SOCK_DGRAM) — connectionless, message boundaries preserved - Address types —
Address.file()for filesystem paths,Address.abstract()for Linux abstract namespace - Client-server —
bind(),listen(),accept(),connect() - File descriptor passing — send and receive fds via SCM_RIGHTS
- Socket pair —
UnixSocket.pair()for intra-process communication - Native buffers — heap-backed and off-heap buffers with zero-copy slicing
- Concurrent I/O —
split()intoSocketReader/SocketWriterhalves - Socket options —
SO_SNDBUF,SO_RCVBUF,SO_LINGER - Non-blocking data check —
hasDatagetter,waitForData(timeout) - Path cleanup —
unlink()/closeAndUnlink()
Installation #
dependencies:
native_socket: ^0.4.0
Note: This package uses Dart native assets (hooks/build system). Enable the experiment when running:
dart --enable-experiment=native-assets runTag releases publish Linux and Android (arm64, arm, x64) prebuilt assets from GitHub Releases. macOS builds use source fallback.
Prerequisites #
- Dart SDK
>=3.8.0 <4.0.0 - Linux, Android, and macOS
- Clang (for native code compilation via hooks)
- Android NDK (for Android builds)
Usage #
Socket pair (intra-process) #
import 'package:native_socket/native_socket.dart';
void main() {
final (a, b) = UnixSocket.pair();
a.send(Uint8List.fromList([0xDE, 0xAD]));
final data = b.receive(1024);
print(data); // [222, 173]
a.close();
b.close();
}
Client-server with bind/connect/accept #
import 'package:native_socket/native_socket.dart';
void main() {
final server = UnixSocket.bind(Address.file('/tmp/my.sock'));
final client = UnixSocket.connect(Address.file('/tmp/my.sock'));
client.send(Uint8List.fromList([0x41, 0x42]));
final conn = server.accept();
final data = conn.receive(1024);
print(data); // [65, 66]
conn.close();
client.close();
server.closeAndUnlink();
}
Datagram sockets (message boundaries preserved) #
import 'package:native_socket/native_socket.dart';
void main() {
final server = UnixSocket.bind(
Address.file('/tmp/dgram.sock'),
type: SocketType.datagram,
);
final client = UnixSocket.create(type: SocketType.datagram);
client.sendTo(Address.file('/tmp/dgram.sock'), Uint8List.fromList([0x01]));
client.sendTo(Address.file('/tmp/dgram.sock'), Uint8List.fromList([0x02, 0x03]));
final first = server.receiveFrom(1024); // [0x01]
final second = server.receiveFrom(1024); // [0x02, 0x03]
client.close();
server.closeAndUnlink();
}
Abstract namespace (Linux only) #
import 'package:native_socket/native_socket.dart';
void main() {
final addr = Address.abstract('my-service');
final server = UnixSocket.bind(addr);
final client = UnixSocket.connect(addr);
// ... no filesystem path to clean up
server.close();
client.close();
}
Native buffers for zero-copy I/O #
import 'package:native_socket/native_socket.dart';
void main() {
// Heap-backed (convenient)
final heapBuf = NativeBuffer.fromList(Uint8List.fromList([1, 2, 3]));
// Native/off-heap (zero-copy for FFI, must free)
final nativeBuf = NativeBuffer.allocate(1024);
nativeBuf.asTypedList()[0] = 0xFF;
// ... use nativeBuf.nativePointer in FFI calls ...
nativeBuf.free();
// Zero-copy slice (shares underlying memory)
final sliced = heapBuf.slice(1, 2); // [2, 3]
}
SCM_RIGHTS file descriptor passing #
import 'package:native_socket/native_socket.dart';
void main() {
final (a, b) = UnixSocket.pair();
final fileFd = createAnonymousFile(4096);
// Send data + fd together
a.send(Uint8List.fromList([0xFF]), fd: fileFd);
// Receive fd (recvmsg reads both data byte and fd)
final receivedFd = b.receiveFd();
closeFd(receivedFd);
closeFd(fileFd);
a.close();
b.close();
}
Socket options #
import 'package:native_socket/native_socket.dart';
void main() {
final (a, _) = UnixSocket.pair();
a.setSendBufferSize(65536);
print(a.getSendBufferSize()); // kernel may round up
a.setLinger(true, 5);
a.close();
}
Split for concurrent read/write #
import 'package:native_socket/native_socket.dart';
void main() {
final (a, b) = UnixSocket.pair();
final (reader, writer) = a.split();
// reader and writer can be used from separate isolates/threads
writer.send(Uint8List.fromList([0x01]));
final data = b.receive(1024);
print(data); // [1]
a.close();
b.close();
}
API Reference #
See the full API docs on pub.dev.
Releases #
Tag builds use native_prebuilt to generate the release manifest and publish
Linux and Android (arm64, arm, x64) release assets on GitHub.
Contributing #
Contributions welcome! Please open issues or submit pull requests on GitHub.