Gibt es bei der Java-Netzwerkprogrammierung eine Möglichkeit, die Server-Seite offen zu halten, auch wenn die Client-Seite heruntergefahren wird?

7

Angenommen, wir haben ein einfaches Echo-Client / Server-Paar in Java. Wie ich es verstehe, sobald eine Seite der Steckdose bricht, ist die ganze Verbindung weg.

Aber was ist, wenn ich einen Server möchte, der immer am Leben bleiben kann, selbst wenn die Client-Seite stirbt? Ich möchte eine unterbrochene Verbindung fortsetzen können.

Echo Server:

%Vor%

irgendwelche Tipps geschätzt danke

    
Coffee 21.07.2015, 06:00
quelle

4 Antworten

11

Was Ihnen fehlt, ist das Konzept einer "Sitzung". Denken Sie über die Position eines Servers nach, wenn einige Bits "auf dem Draht" ankommen. Was damit zu tun? Bei TCP / IP sind bereits einige Informationen auf dem Draht vorhanden:

  • src addr
  • src port
  • Zieladresse
  • Zielport
  • und die Nachrichtennutzlast selbst
  • und andere Dinge (wie Sequenzzähler, um sicherzustellen, dass "Pakete" während der Übertragung nicht durcheinander gebracht werden)

Das Betriebssystem des Servers verwendet die Informationen src / dest addr / port, um zu entscheiden, ob es sich um eine gerade laufende Konversation handelt oder nicht. Hauptsächlich betrachtet es die dest port (da die Nachricht bereits über das Internet und die Firewall an die Maschine selbst gesendet wurde), um zu entscheiden, ob es für Ihr Java-Programm ist, auf den 'Zielport' zu hören. Es wird jedoch der gesamte src-addr / src-port / dest-addr / dest-port verwendet, um die Nutzdaten an Ihr Programm zu senden in der Reihenfolge, in der der Absender sie gesendet hat (möglicherweise nicht die Reihenfolge, in der sie wegen des intervenierenden Netzes kamen). Beachten Sie, dass eine einzelne "Nachricht" tatsächlich in mehrere Pakete aufgeteilt werden kann. Der TCP / IP-Stack Ihres Betriebssystems macht Ihnen eine Menge Arbeit.

Beachten Sie jedoch, dass das Betriebssystem einige Ressourcen zur Verfolgung des Status der TCP / IP-Sitzung aufwenden muss, um diese Funktion in Ihrem Auftrag ausführen zu können. Zumindest muss für jeden Satz von Port / Adr src / dest ein Zähler des letzten gut empfangenen "Pakets" vorhanden sein, etwas Pufferraum, um die Pakete zu halten, bis Ihr Programm bereit ist, sie zu verbrauchen, und so weiter her.

Nun stellt sich die Frage, der der TCP / IP-Stack-Implementor gegenübersteht, "Wie lange sollte ich in diesem Zustand bleiben?" Sind 10 Sekunden genug? 20 Minuten? Nachdem die Sitzung für einige Zeit nicht mehr vom Client gehört wurde, muss die Sitzung "Timeout" sein. Wenn in einer Sequenz mehr Pakete gesendet werden und der Client sie erneut zu senden beginnt, muss der Server in der Lage sein zu sagen: "Entschuldigung, Sie senden mir Paket 234 einer früheren Nachricht, aber weil ich nichts davon gehört habe Sie für eine Weile, warf ich Pakete 1-233. Könnten wir wieder von vorne anfangen? ".

In diesem Sinne gibt es keine Möglichkeit, den Client daran zu hindern, sich zu trennen. Sicher, Sie können weiter auf den Socket hören, falls der Client sich erholt und weitere Daten sendet. Aber Sie und Ihr Kunde werden einen Weg brauchen, um dort weiterzumachen, wo wir aufgehört haben.

In HTTP wird dies mit einem Sitzungscookie erreicht - einem langen eindeutigen String, den der Server dem Client gegeben hat, und der Client sendet mit jeder neuen Anfrage erneut (ob es über dieselbe Sitzung auf TCP-Ebene stattfindet oder nicht) ). Dies ist eine Sitzung auf Anwendungsebene, deren Lebensdauer länger ist als die der TCP-Sitzung.

Da Sie eine Anwendung schreiben und es sich anhört, als hätten Sie ein gewisses Maß an Kontrolle darüber, was der Client und der Server miteinander zu tun haben (das "Protokoll"), haben Sie mehr Möglichkeiten, wie Sie dem zustimmen Was ist eine Sitzung, wie geht man mit den Dingen um, wenn der Klient "weggeht" (Timeout der Sitzung) und wie sich beide Seiten erholen und "dort weitermachen, wo wir aufgehört haben" (Sitzung neu aufbauen). Vergessen Sie nicht über die Authentifizierung werden Sie!

Wie andere gesagt haben, hängt es sehr davon ab, was Sie erreichen wollen.

    
David Bullock 04.11.2015 11:45
quelle
5

Wenn Sie einen Server und mehrere Clients erstellen möchten, erstellen wir normalerweise einen Thread, der für die Kommunikation zwischen dem Server und einem der Clients zuständig ist. Jedes Mal, wenn sich ein Client mit dem Server verbindet, startet der Server ein neuer Thread und gibt ihm den entsprechenden Socket.

Der Code sollte etwa so aussehen:

%Vor%

Und die ClientHandler-Klasse:

%Vor%     
Lourenco 21.07.2015 06:21
quelle
4

Wie jemand darauf hingewiesen hat, können Sie dies nicht mit TCP tun.

Hier ist ein einfaches Beispiel für einen DatagramSocket (UDP) Echo Server.

%Vor%

Update: Testinformationen hinzugefügt

Sie können es mit nc

testen %Vor%     
gustf 27.02.2016 20:04
quelle
0

Bei Verwendung der Socket-API, wie in Ihrem Code gezeigt, sollte dies kein Problem darstellen. Für eine einzelne Verbindung, wenn eine der beiden Seiten geschlossen wird (oder stirbt) Die vollständige Zuordnung ist "down" und kann nicht mehr verwendet werden. Dies geschieht mit clientSocket über Ihren Code.

ServerSocket ist jedoch weiterhin offen und akzeptiert neue Verbindungen. In diesem Zusammenhang bleibt Ihr Server immer "am Leben".

Ihr gezeigter Code ist also ein einfaches Beispiel für die Verwendung von Socket-API, um einen Server zu erstellen, der auf eingehende Verbindungen wartet und die einzelnen (eingehenden) Aufrufe zur Verarbeitung absetzt.

Der einzige "Nachteil" Ihres Codes besteht darin, dass Ihr Server nicht in der Lage ist, auf neue Anforderungen zu reagieren, indem er im selben Thread wie accept () verarbeitet solange es die vorherigen verarbeitet. Um diese Verarbeitung zu vermeiden, könnte es sein an einen neuen Thread delegiert (wie bereits erwähnt).

Weitere Erläuterungen finden Sie in der Dokumentation zu accept (). z.B. Sie können die Socket-API-Erklärung

durchlesen

Bitte beachten Sie, dies ist nicht direkt eine Java-Frage. Java envopt und stellt Java-Programmen die Funktionalität des zugrundeliegenden Betriebssystems in Bezug auf Socket-Kommunikation zur Verfügung. Das ist meistens was ist dokumentiert als Teil des Posix-Standards, ist dies tatsächlich (in Bezug auf Sockets) nur wiederholen (und aggregieren), was mit verschiedenen RFCs angegeben wurde (siehe Details zu dieser Spezifikation).

Mit Sockets, die eine Verbindung offen halten (funktionieren in vollem Umfang), nachdem eine Seite sie beendet hat, ist nicht möglich, wenn der Socket auf das TCP-Protokoll eingestellt ist. Es gibt - nur um Vollständigkeit hinzuzufügen - einen Mechanismus (shutdown), um zu deklarieren, dass die lokale sendende Seite heruntergefahren ist, während noch weitere Daten für die Eingabe akzeptiert werden. (Aber ich nehme an, wir sprechen nicht über dieses besondere Feature.) Eine Verbindung offen zu halten, wenn die verbundene Seite sich weigert zu sprechen, würde logische Probleme verursachen und wäre auch ein Alptraum für die Ressourcenverwaltung. (Wie lange würde der Server die Ressourcen behalten?)

Das Standardmuster für die Verwendung von TCP mit einem Daemon (ein Prozess, der fortwährend einen Dienst an einem bestimmten Port bereitstellt) erfolgt mittels accept () wie oben angegeben:

  • Der Daemon läuft auf accept ().
  • Ein Client ruft connect () zum Server
  • auf
  • accept () gibt eine neue (dedizierte) Verbindung zur Kommunikation mit dem Client
  • zurück
  • Client und Server tauschen Daten aus
  • eine Seite (Client oder Server) beendet die Verbindung.

Die Strategie, die der Server zum Ausführen mehrerer Anfragen verwendet (synchrone Verarbeitung einer nach dem anderen, Anforderungswarteschlangen, ein Thread pro Verbindung ist eine vollständig separate Entwurfsentscheidung. Sie hängt vom Grad der Parallelität, den verfügbaren Ressourcen usw. ab.

Der Server wird zwei verschiedene "Arten" von Sockets haben:

  1. Der Socket, den es aufruft, accept () on ist derjenige, auf den der Server für eingehende Verbindungen "hört".
    Dieser Sockel ist derjenige, der ständig geöffnet ist.
  2. Ein Socket, das von accept () zurückgegeben wird, ist für eine bestimmte Verbindung.
    Dies wird für die Kommunikation mit einem bestimmten Kunden verwendet und wird "sterben" am Ende der Interaktion.
rpy 04.03.2016 07:30
quelle

Tags und Links