Java Unix Domain Socket implementation providing AF_UNIX, AF_TIPC, AF_VSOCK, and AF_SYSTEM socket support with traditional and NIO APIs
—
High-performance, non-blocking I/O implementation with full Java NIO integration for scalable socket operations and event-driven programming using Unix Domain Sockets.
NIO socket channel implementation for non-blocking Unix Domain Socket client connections.
/**
* Unix Domain Socket NIO channel implementation
*/
public final class AFUNIXSocketChannel extends AFSocketChannel {
/**
* Opens a new AFUNIXSocketChannel
* @return New AFUNIXSocketChannel instance
* @throws IOException if channel creation fails
*/
public static AFUNIXSocketChannel open() throws IOException;
/**
* Opens and connects a new AFUNIXSocketChannel to the specified address
* @param remote The address to connect to
* @return Connected AFUNIXSocketChannel instance
* @throws IOException if connection fails
*/
public static AFUNIXSocketChannel open(AFUNIXSocketAddress remote) throws IOException;
// Connection operations
public boolean connect(SocketAddress remote) throws IOException;
public boolean finishConnect() throws IOException;
public boolean isConnectionPending();
// Channel configuration
public AFUNIXSocketChannel configureBlocking(boolean block) throws IOException;
public boolean isBlocking();
public SelectionKey register(Selector sel, int ops) throws ClosedChannelException;
public SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException;
// I/O operations
public int read(ByteBuffer dst) throws IOException;
public int write(ByteBuffer src) throws IOException;
public long read(ByteBuffer[] dsts) throws IOException;
public long write(ByteBuffer[] srcs) throws IOException;
// Socket properties
public AFUNIXSocket socket();
public AFUNIXSocketAddress getLocalAddress() throws IOException;
public AFUNIXSocketAddress getRemoteAddress() throws IOException;
// Channel state
public boolean isOpen();
public boolean isConnected();
public void close() throws IOException;
}Usage Examples:
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.charset.StandardCharsets;
import org.newsclub.net.unix.*;
// Basic non-blocking client
AFUNIXSocketAddress serverAddr = AFUNIXSocketAddress.of(new File("/tmp/server.sock"));
try (AFUNIXSocketChannel channel = AFUNIXSocketChannel.open()) {
channel.configureBlocking(false);
// Initiate connection
boolean connected = channel.connect(serverAddr);
if (!connected) {
// Connection pending, wait for completion
while (!channel.finishConnect()) {
Thread.sleep(10);
}
}
// Send data
String message = "Hello from NIO client";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));
while (buffer.hasRemaining()) {
channel.write(buffer);
}
// Read response
ByteBuffer responseBuffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(responseBuffer);
responseBuffer.flip();
byte[] responseData = new byte[bytesRead];
responseBuffer.get(responseData);
String response = new String(responseData, StandardCharsets.UTF_8);
System.out.println("Server response: " + response);
}
// Blocking channel for simpler usage
try (AFUNIXSocketChannel channel = AFUNIXSocketChannel.open(serverAddr)) {
// Channel is blocking by default and already connected
ByteBuffer writeBuffer = ByteBuffer.wrap("Hello Server".getBytes(StandardCharsets.UTF_8));
channel.write(writeBuffer);
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(readBuffer);
readBuffer.flip();
String response = StandardCharsets.UTF_8.decode(readBuffer).toString();
System.out.println("Response: " + response);
}NIO server socket channel implementation for accepting Unix Domain Socket connections in non-blocking mode.
/**
* Unix Domain Socket NIO server channel implementation
*/
public final class AFUNIXServerSocketChannel extends AFServerSocketChannel {
/**
* Opens a new AFUNIXServerSocketChannel
* @return New AFUNIXServerSocketChannel instance
* @throws IOException if channel creation fails
*/
public static AFUNIXServerSocketChannel open() throws IOException;
// Server operations
public AFUNIXServerSocket socket();
public AFUNIXSocketChannel accept() throws IOException;
public AFUNIXServerSocketChannel bind(SocketAddress local) throws IOException;
public AFUNIXServerSocketChannel bind(SocketAddress local, int backlog) throws IOException;
// Channel configuration
public AFUNIXServerSocketChannel configureBlocking(boolean block) throws IOException;
public boolean isBlocking();
public SelectionKey register(Selector sel, int ops) throws ClosedChannelException;
public SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException;
// Server properties
public AFUNIXSocketAddress getLocalAddress() throws IOException;
public boolean isOpen();
public void close() throws IOException;
}Usage Examples:
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;
import org.newsclub.net.unix.*;
// Basic server with selector
AFUNIXSocketAddress serverAddr = AFUNIXSocketAddress.of(new File("/tmp/nio-server.sock"));
try (AFUNIXServerSocketChannel serverChannel = AFUNIXServerSocketChannel.open();
Selector selector = Selector.open()) {
serverChannel.configureBlocking(false);
serverChannel.bind(serverAddr);
// Register server channel for accept operations
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIO Server listening on: " + serverAddr.getFile());
while (!Thread.interrupted()) {
int readyChannels = selector.select(1000); // 1 second timeout
if (readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
if (key.isAcceptable()) {
handleAccept(serverChannel, selector);
} else if (key.isReadable()) {
handleRead(key);
}
}
}
}
// Helper methods for server operations
private static void handleAccept(AFUNIXServerSocketChannel serverChannel, Selector selector) throws IOException {
AFUNIXSocketChannel clientChannel = serverChannel.accept();
if (clientChannel != null) {
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Accepted connection from: " + clientChannel.getRemoteAddress());
}
}
private static void handleRead(SelectionKey key) throws IOException {
AFUNIXSocketChannel clientChannel = (AFUNIXSocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
int bytesRead = clientChannel.read(buffer);
if (bytesRead > 0) {
buffer.flip();
// Echo back the data
while (buffer.hasRemaining()) {
clientChannel.write(buffer);
}
} else if (bytesRead < 0) {
// Client closed connection
clientChannel.close();
key.cancel();
}
} catch (IOException e) {
clientChannel.close();
key.cancel();
}
}NIO datagram channel implementation for non-blocking Unix Domain Socket datagram communication.
/**
* Unix Domain Socket NIO datagram channel implementation
*/
public final class AFUNIXDatagramChannel extends AFDatagramChannel {
/**
* Opens a new AFUNIXDatagramChannel
* @return New AFUNIXDatagramChannel instance
* @throws IOException if channel creation fails
*/
public static AFUNIXDatagramChannel open() throws IOException;
// Datagram operations
public int send(ByteBuffer src, SocketAddress target) throws IOException;
public SocketAddress receive(ByteBuffer dst) throws IOException;
public AFUNIXDatagramChannel connect(SocketAddress remote) throws IOException;
public AFUNIXDatagramChannel disconnect() throws IOException;
// Channel configuration
public AFUNIXDatagramChannel configureBlocking(boolean block) throws IOException;
public boolean isBlocking();
public AFUNIXDatagramChannel bind(SocketAddress local) throws IOException;
// Channel properties
public AFUNIXDatagramSocket socket();
public AFUNIXSocketAddress getLocalAddress() throws IOException;
public AFUNIXSocketAddress getRemoteAddress() throws IOException;
public boolean isConnected();
// I/O operations (when connected)
public int read(ByteBuffer dst) throws IOException;
public int write(ByteBuffer src) throws IOException;
}Usage Examples:
import java.nio.ByteBuffer;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import org.newsclub.net.unix.*;
// Datagram sender
AFUNIXSocketAddress targetAddr = AFUNIXSocketAddress.of(new File("/tmp/datagram-target.sock"));
try (AFUNIXDatagramChannel senderChannel = AFUNIXDatagramChannel.open()) {
String message = "Hello via NIO datagram";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));
int bytesSent = senderChannel.send(buffer, targetAddr);
System.out.println("Sent " + bytesSent + " bytes");
}
// Datagram receiver
AFUNIXSocketAddress receiverAddr = AFUNIXSocketAddress.of(new File("/tmp/datagram-receiver.sock"));
try (AFUNIXDatagramChannel receiverChannel = AFUNIXDatagramChannel.open()) {
receiverChannel.bind(receiverAddr);
receiverChannel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
SocketAddress senderAddr = receiverChannel.receive(buffer);
if (senderAddr != null) {
buffer.flip();
String message = StandardCharsets.UTF_8.decode(buffer).toString();
System.out.println("Received from " + senderAddr + ": " + message);
}
}
// Connected datagram channel
try (AFUNIXDatagramChannel channel = AFUNIXDatagramChannel.open()) {
channel.connect(targetAddr);
// Can use read/write methods when connected
ByteBuffer writeBuffer = ByteBuffer.wrap("Connected message".getBytes(StandardCharsets.UTF_8));
channel.write(writeBuffer);
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(readBuffer);
if (bytesRead > 0) {
readBuffer.flip();
String response = StandardCharsets.UTF_8.decode(readBuffer).toString();
System.out.println("Response: " + response);
}
}Custom selector provider for Unix Domain Socket channels enabling efficient event-driven programming.
/**
* Unix Domain Socket selector provider
*/
public final class AFUNIXSelectorProvider extends AFSelectorProvider {
/**
* Gets the system-wide default AFUNIXSelectorProvider
* @return AFUNIXSelectorProvider instance
*/
public static AFUNIXSelectorProvider provider();
/**
* Gets a new AFUNIXSelectorProvider instance
* @return New AFUNIXSelectorProvider instance
*/
public static AFUNIXSelectorProvider getInstance();
// Channel creation
public AFUNIXSocketChannel openSocketChannel() throws IOException;
public AFUNIXServerSocketChannel openServerSocketChannel() throws IOException;
public AFUNIXDatagramChannel openDatagramChannel() throws IOException;
// Selector creation
public AbstractSelector openSelector() throws IOException;
public Pipe openPipe() throws IOException;
}Usage Examples:
import java.nio.channels.Selector;
import java.nio.channels.Pipe;
import org.newsclub.net.unix.*;
// Using custom selector provider
AFUNIXSelectorProvider provider = AFUNIXSelectorProvider.getInstance();
// Create channels through provider
try (AFUNIXSocketChannel socketChannel = provider.openSocketChannel();
AFUNIXServerSocketChannel serverChannel = provider.openServerSocketChannel();
AFUNIXDatagramChannel datagramChannel = provider.openDatagramChannel()) {
// Configure channels
socketChannel.configureBlocking(false);
serverChannel.configureBlocking(false);
datagramChannel.configureBlocking(false);
// Create selector through provider
try (Selector selector = provider.openSelector()) {
// Register channels with selector
socketChannel.register(selector, SelectionKey.OP_CONNECT);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
datagramChannel.register(selector, SelectionKey.OP_READ);
// Event loop
while (!Thread.interrupted()) {
int readyChannels = selector.select();
if (readyChannels > 0) {
// Process selected keys
processSelectedKeys(selector);
}
}
}
}
// Pipe creation for inter-thread communication
try (Pipe pipe = provider.openPipe()) {
Pipe.SourceChannel sourceChannel = pipe.source();
Pipe.SinkChannel sinkChannel = pipe.sink();
// Configure pipe channels
sourceChannel.configureBlocking(false);
sinkChannel.configureBlocking(false);
// Use pipe for thread communication
// ... pipe operations
}// Selection key operations
public SelectionKey register(Selector sel, int ops) throws ClosedChannelException;
public SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException;
// Interest operations
public static final int OP_READ = 1;
public static final int OP_WRITE = 4;
public static final int OP_CONNECT = 8;
public static final int OP_ACCEPT = 16;Advanced Selector Example:
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
// Multi-client NIO server with client tracking
public class AdvancedNIOServer {
private final Map<SelectionKey, ClientHandler> clients = new ConcurrentHashMap<>();
public void runServer(AFUNIXSocketAddress serverAddr) throws IOException {
try (AFUNIXServerSocketChannel serverChannel = AFUNIXServerSocketChannel.open();
Selector selector = Selector.open()) {
serverChannel.configureBlocking(false);
serverChannel.bind(serverAddr);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (!Thread.interrupted()) {
if (selector.select(1000) > 0) {
processKeys(selector, serverChannel);
}
}
}
}
private void processKeys(Selector selector, AFUNIXServerSocketChannel serverChannel) throws IOException {
Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
try {
if (key.isAcceptable()) {
acceptClient(serverChannel, selector);
} else if (key.isReadable()) {
readFromClient(key);
} else if (key.isWritable()) {
writeToClient(key);
}
} catch (IOException e) {
closeClient(key);
}
}
}
private void acceptClient(AFUNIXServerSocketChannel serverChannel, Selector selector) throws IOException {
AFUNIXSocketChannel clientChannel = serverChannel.accept();
if (clientChannel != null) {
clientChannel.configureBlocking(false);
SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ);
ClientHandler handler = new ClientHandler(clientChannel);
clients.put(clientKey, handler);
clientKey.attach(handler);
}
}
private void readFromClient(SelectionKey key) throws IOException {
ClientHandler handler = clients.get(key);
if (handler != null) {
boolean keepOpen = handler.handleRead();
if (!keepOpen) {
closeClient(key);
}
}
}
private void writeToClient(SelectionKey key) throws IOException {
ClientHandler handler = clients.get(key);
if (handler != null) {
handler.handleWrite();
}
}
private void closeClient(SelectionKey key) {
clients.remove(key);
try {
key.channel().close();
} catch (IOException e) {
// Log error
}
key.cancel();
}
private static class ClientHandler {
private final AFUNIXSocketChannel channel;
private final ByteBuffer readBuffer = ByteBuffer.allocate(1024);
private final ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
public ClientHandler(AFUNIXSocketChannel channel) {
this.channel = channel;
}
public boolean handleRead() throws IOException {
readBuffer.clear();
int bytesRead = channel.read(readBuffer);
if (bytesRead < 0) {
return false; // Client closed connection
}
if (bytesRead > 0) {
readBuffer.flip();
// Process read data and prepare response
prepareResponse();
}
return true;
}
public void handleWrite() throws IOException {
if (writeBuffer.hasRemaining()) {
channel.write(writeBuffer);
}
}
private void prepareResponse() {
// Echo the data back
writeBuffer.clear();
writeBuffer.put(readBuffer);
writeBuffer.flip();
}
}
}// Efficient buffer operations
ByteBuffer directBuffer = ByteBuffer.allocateDirect(8192);
ByteBuffer heapBuffer = ByteBuffer.allocate(8192);
// Scatter-gather I/O
ByteBuffer[] buffers = new ByteBuffer[3];
buffers[0] = ByteBuffer.allocate(1024);
buffers[1] = ByteBuffer.allocate(2048);
buffers[2] = ByteBuffer.allocate(1024);
long totalBytesRead = channel.read(buffers);
long totalBytesWritten = channel.write(buffers);NIO-specific exception handling patterns:
// Channel exceptions
public class ClosedChannelException extends IOException;
public class NotYetConnectedException extends IllegalStateException;
public class AlreadyConnectedException extends IllegalStateException;
public class ConnectionPendingException extends IllegalStateException;
public class NoConnectionPendingException extends IllegalStateException;Error Handling Examples:
try (AFUNIXSocketChannel channel = AFUNIXSocketChannel.open()) {
channel.configureBlocking(false);
if (!channel.connect(serverAddr)) {
// Connection pending
while (!channel.finishConnect()) {
Thread.sleep(10);
}
}
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(buffer);
} catch (ClosedChannelException e) {
System.err.println("Channel was closed: " + e.getMessage());
} catch (NotYetConnectedException e) {
System.err.println("Channel not connected: " + e.getMessage());
} catch (AlreadyConnectedException e) {
System.err.println("Channel already connected: " + e.getMessage());
} catch (ConnectionPendingException e) {
System.err.println("Connection already pending: " + e.getMessage());
} catch (IOException e) {
System.err.println("I/O error: " + e.getMessage());
}Install with Tessl CLI
npx tessl i tessl/maven-com-kohlschutter-junixsocket--junixsocket-core