Eine sehr grundlegende Methode zur bidirektionalen Interprozesskommunikation zwischen verteilten Software-Komponenten ist die Verwendung von Internet-Sockets. Ein Internet-Socket ist ein interner Endpunkt aus Sicht einer Anwendung zum Senden und Empfangen von Daten in einem Netzwerk auf Basis des Internet-Protokolls (IP). Der Begriff Socket selbst geht urspünglich auf den RFC 147 von 1971 zurück, der sich noch auf das ARPA-Netzwerk bezieht. Ein Socket wird einer Anwendung vom Betriebssystem auf Anforderung unter einem bestimmten Port bereitgestellt. Das Betriebssystem verwaltet die aktuell aktiven, lokalen Sockets und die zugehörigen Remote-Sockets (IP-Adressen und Ports). Internet-Sockets lassen sich in Stream Sockets (TCP) und Datagram Sockets (UDP) unterscheiden. Im folgenden soll die Java-API für Stream Sockets vorgestellt werden, die im Package java.net implementiert und damit Bestandteil des Moduls java.base ist.

Das Code-Beispiel zeigt eine einfache Chat-Anwendung ähnlich des Beispiels im Kapitel WebSockets.

import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedReader;
import java.io.PrintWriter;
// ...

public class ChatServer {

    static Set<PrintWriter> clientWriters = new HashSet<>();

    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(5000);
			
            while (true) {
                // wait for new client connection
                Socket clientSocket = serverSocket.accept();
                System.out.println(">>> Client connected from " + clientSocket.getRemoteSocketAddress());

                // create output writer
                PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());
                clientWriters.add(writer);

                // create input reader
                BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

                // start concurrent message handler
                new Thread(new BroadcastMessageHandler(reader)).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void broadcast(String message) {
        for (PrintWriter writer : clientWriters) {
            writer.println(message);
            writer.flush();
        }
    }
}
public class BroadcastMessageHandler extends MessageHandler {

    public BroadcastMessageHandler(BufferedReader reader) {
        super(reader);
    }

    @Override
    public void onMessage(String message) {
        super.onMessage(message);
        ChatServer.broadcast(message);
    }
}
public class MessageHandler implements Runnable {

    BufferedReader reader;

    public MessageHandler(BufferedReader reader) {
        this.reader = reader;
    }

    @Override
    public void run() {
        String message;
        try {
            while ((message = reader.readLine()) != null) {
                onMessage(message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void onMessage(String message) {
        System.out.println(">>> Received: '" + message + "'");
    }
}
public class ChatClient {

    static Socket socket;
    static PrintWriter writer;

    public static void main(String[] args) {
        try {
            // connect to server
            socket = new Socket("127.0.0.1", 5000);
            System.out.println(">>> Client connected using port " + socket.getLocalPort());			

            // create output writer
            writer = new PrintWriter(socket.getOutputStream());

            // create input reader
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            // start concurrent message handler
            new Thread(new MessageHandler(reader)).start();

        } catch (IOException e) {
            e.printStackTrace();
        }

        // Wait for messages to send to the server
        while (true) {
            System.out.println(">>> Write your message:");
            Scanner scanner = new Scanner(System.in);
            writer.println(scanner.next());
            writer.flush();
        }
    }
}

Über einen ObjectOutputStream können auch Objekte versendet werden, die das Serializable-Interface unterstützen. Sender und Empfänger müssen die entsprechenden Klassen zu den versendeten Objekten untereinander austauschen. Der Empfänger kann über instanceof ermitteln, von welchem Typ das empfangene Objekt ist.

Object object = inputStream.readObject();
if(object instanceof Message) {
	Message message = (Message) object;
}

Die gezeigten Code-Beispiele zu Sockets finden sich im Verzeichnis /remote/socket des Modul-Repository.