CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-kohlschutter-junixsocket--junixsocket-core

Java Unix Domain Socket implementation providing AF_UNIX, AF_TIPC, AF_VSOCK, and AF_SYSTEM socket support with traditional and NIO APIs

Pending
Overview
Eval results
Files

nio-channels.mddocs/

NIO Channels

High-performance, non-blocking I/O implementation with full Java NIO integration for scalable socket operations and event-driven programming using Unix Domain Sockets.

Capabilities

AFUNIXSocketChannel

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);
}

AFUNIXServerSocketChannel

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();
    }
}

AFUNIXDatagramChannel

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);
    }
}

AFUNIXSelectorProvider

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
}

Advanced NIO Features

Channel Selectors and Event Handling

// 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();
        }
    }
}

Buffer Management and Performance

// 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);

Error Handling

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

docs

addressing.md

capabilities.md

datagram-sockets.md

exceptions.md

file-descriptors.md

index.md

nio-channels.md

rmi.md

socket-pairs.md

unix-sockets.md

utilities.md

tile.json