2 Stimmen

Zuverlässiges TCP/IP in Java

Gibt es eine Möglichkeit, eine zuverlässige Kommunikation (der Sender wird informiert, dass die gesendete Nachricht bereits vom Empfänger empfangen wurde) mit der Java TCP/IP-Bibliothek in java.net.* zu erreichen? Ich weiß, dass einer der Vorteile von TCP gegenüber UDP seine Zuverlässigkeit ist. Dennoch konnte ich diese Gewissheit in dem folgenden Experiment nicht erlangen:

Ich habe zwei Klassen erstellt:

1) Echo-Server => sendet immer die Daten zurück, die er empfangen hat.

2) Client => sendet in regelmäßigen Abständen die Nachricht "Hello world" an den Echo-Server.

Sie wurden auf verschiedenen Computern ausgeführt (und funktionierten einwandfrei). Mitten in der Ausführung trennte ich das Netzwerk (zog das LAN-Kabel ab). Nachdem die Verbindung getrennt wurde, wartete der Server immer noch auf Daten, bis einige Sekunden vergangen waren (schließlich löste er eine Ausnahme aus). Ebenso sendet der Client weiterhin Daten, bis ein paar Sekunden vergangen sind (eine Ausnahme wird ausgelöst).

Das Problem ist, objectOutputStream.writeObject(message) garantiert nicht den Zustellungsstatus der Nachricht (ich erwarte, dass es den Thread blockiert und die Daten erneut sendet, bis sie zugestellt sind). Oder ich werde zumindest darüber informiert, welche Nachrichten fehlen.

Server-Code:

import java.net.*;
import java.io.*;

import java.io.Serializable;

public class SimpleServer {
    public static void main(String args[]) {
        try {
            ServerSocket serverSocket = new ServerSocket(2002);
            Socket socket = new Socket();
            socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            ObjectInputStream objectInputStream = new ObjectInputStream(
                    inputStream);

            while (true) {
                try {
                    String message = (String) objectInputStream.readObject();
                    System.out.println(message);
                    Thread.sleep(1000);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Client-Code:

import java.net.*;
import java.io.*;

public class SimpleClient {
    public static void main(String args[]) {
        try {
            String serverIpAddress = "localhost"; //change this

            Socket socket = new Socket(serverIpAddress, 2002);
            OutputStream outputStream = socket.getOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(
                    outputStream);

            while (true) {
                String message = "Hello world!";
                objectOutputStream.writeObject(message);

                System.out.println(message);
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3voto

user207421 Punkte 297318

Wenn Sie wissen müssen, welche Nachrichten in der Peer-Anwendung angekommen sind, muss die Peer-Anwendung Bestätigungen senden.

3voto

Peter Lawrey Punkte 511323

Wenn Sie dieses Maß an Garantien wünschen, scheint es, als ob Sie wirklich JMS wollen. Damit kann nicht nur sichergestellt werden, dass die Nachrichten zugestellt wurden, sondern auch, dass sie korrekt verarbeitet wurden, d.h. es hat keinen Sinn, eine sehr zuverlässige Zustellung zu haben, wenn sie aufgrund eines Fehlers verworfen werden kann.

Sie können überwachen, welche Nachrichten warten und welche Verbraucher im Rückstand sind. Überwachen Sie einen Producer, um zu sehen, welche Nachrichten er sendet, und lassen Sie Nachrichten speichern, wenn er ausfällt und beim Neustart zur Verfügung steht, d. h. zuverlässige Zustellung, auch wenn der Consumer neu gestartet wird.

1voto

Chris Dennett Punkte 21894

TCP ist immer zuverlässig. Sie brauchen keine Bestätigungen. Um jedoch zu überprüfen, ob ein Client erreichbar ist, können Sie auch einen UDP-Stream mit Bestätigungen verwenden. Wie ein PING? PONG!-System. Möglicherweise gibt es auch TCP-Einstellungen, die Sie anpassen können.

1voto

Heiko Rupp Punkte 29262

Ihre Grundannahme (und Ihr Verständnis von TCP) ist hier falsch. Wenn Sie den Stecker abziehen und wieder einstecken, geht die Nachricht höchstwahrscheinlich nicht verloren.
Es kommt darauf an, wie lange der Absender warten soll. Eine Stunde, einen Tag? Wenn Sie die Zeitüberschreitung auf einen Tag festlegen, würden Sie zwei Tage lang den Stecker ziehen und immer noch "funktioniert nicht" sagen.

Die Liefergarantie lautet also: "Entweder werden die Daten geliefert - oder Sie werden informiert". Im zweiten Fall müssen Sie das Problem auf Anwendungsebene lösen.

1voto

Adamski Punkte 52945

Sie könnten die Socket-Option SO_KEEPALIVE verwenden, die bewirkt, dass die Verbindung geschlossen wird, wenn 2 Stunden lang keine Daten über den Socket übertragen werden. Allerdings bietet dies in vielen Fällen nicht die Kontrolle, die Anwendungen normalerweise benötigen.

Ein zweites Problem ist, dass einige TCP/IP-Stack-Implementierungen schlecht sind und Ihren Server bei einem Netzwerkausfall mit offenen Verbindungen zurücklassen können.

Daher würde ich empfehlen, ein Heartbeating auf Anwendungsebene zwischen Client und Server einzufügen, um sicherzustellen, dass beide Parteien noch am Leben sind. Dies hat auch den Vorteil, dass die Verbindung getrennt werden kann, wenn z. B. ein Drittanbieter-Client zwar noch lebt, aber nicht mehr reagiert und daher keine Heartbeats mehr sendet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X