# Abbruch eines Programmes abfangen



## Hindi93 (9. Apr 2011)

Hi,
ich hoffe ich bin hier im richtigem Forum, da es sich auch um Sockets handelt, aber wie auch immer.
Wenn ich einen  Socket erstelle, der sich vom Client zu einem Server verbindet, den Clienten dann aber einfach abkacken lasse in dem ich das Programm einfach beendet, besteht die Socket Verbindung zum Server trotzdem noch. Jetzt die Frage:
Wie kann ich denn vom Server dann noch feststellen ob der Client noch exisitert bzw. noch auf den Server zugreift?

mfg Hindi


----------



## maki (9. Apr 2011)

> ich hoffe ich bin hier im richtigem Forum, da es sich auch um Sockets handelt, aber wie auch immer.


Nö, Sockets -> Netzwerk
Es geht nicht um den Fragesteller sondern um die Frage 

*verschoben*


----------



## Antoras (9. Apr 2011)

Du könntest einen Timeout setzen, was die Verbindung ungültig werden lässt sobald längere Zeit keine Eingabe getätigt wurde.
Oder du schickt in regelmäßigen Abständen Nachrichten an den Client und wenn er nicht antwortet kannst du ihn für offline erklären.


----------



## Volvagia (9. Apr 2011)

Ist das nicht nur bei DatagramSockets (UDP) so, da es ja keine "echte" Verbindung gibt? Bei Sockets fliegt dir doch beim nächsten Leseversuch eine SocketException. ("Connection resettet by peer" oder so ähnlich). Dementsprechend wird der nächste Leseversuch mit "null" enden, auf das brauchst du danach, wo du die verschiedenen einkommenden Daten handles einfach nur zu prüfen und socket.close() aufzurufen bzw. den Lesethread herunterfahren.


----------



## FArt (9. Apr 2011)

Oft muss man sich gar nicht mit Sockets rumschlagen. Da gibt es schon ganz tolle Frameworks, die Zusatzfunktionalität bereitstellen, z.B. JBoss Remoting oder Mina. Da gibt es z.B. so etwas wie einen Lease Ping, der automatisch die Verbindungen überwacht und dich bei gekappter Verbindung über einen Callback benachrichtigt.


----------



## zeugwart (12. Jun 2012)

Hallo zusammen,

da ich logisch gesehen das selbe Problem wie Hindi93 habe, dacht ich, ich knüpfe hier nahtlos an...

*Mein Szenario:* Auf einer kleinen Hardware, quasi als Blackbox zu sehen, läuft ein Server. Zu 
diesem baue ich einen gewöhnlichen Java-Socket auf. Soweit so gut.
Der Client (Java) hat dabei eine etwas eigenartige Rolle, er dient, und darf auch nur als Tunnel dienen.
(So die Vorgaben) Sprich im Client selbst, darf ich nicht wild auf den Socket senden.

*Mein Problem: *Die kleine Hardware, auf der der Server läuft, wird durch die Gegend getragen, 
verliert kurzzeitig, oder auch längerfristig, den Empfang oder es fällt der Strom aus oder oder oder...
Am Ende steht ein Client(Socket) mit loser Verbindung. Von Außen werden nun Daten in den Client 
geschickt, der diese an den Server weiterleiten soll. Der leitet die Daten jetzt ins Nichts.

Wenn ich irgendwie feststellen könnte, dass die Verbindung unterbrochen wurde, könnte sie einfach 
neu aufgebaut werden (Das soll autonom passieren)

Nur! ich stelle nichts fest, nie, mit nichts!

*Mein Gedankengang:*

Eine Socketverbindung wird doch über das TCP-Protokoll realisiert. Wenn nun Daten über einen Writer 
auf den toten Socket geschrieben werden, so meine Denke, sollte doch schon das Protokoll feststellen,
dass die Gegenseite nicht antwortet. Dieser Umstand müsste doch - wie auch immer - an die JRE 
weitergeleitet werden und ich würde da ne Exception erwarten.

Das geht in die Richtung von Volvagia im Post vorher: 





> Bei Sockets fliegt dir doch beim
> nächsten Leseversuch eine SocketException



*Mein Code:* (zumindest der wesentliche Teil)
	
	
	
	





```
@Override
	public void run() {
		
		try {
			
			boolean enableSend = true;		  
			PrintStream ps = new PrintStream(os, true); 
			BufferedReader buff = new BufferedReader(new InputStreamReader(is));

			this.socket = new Socket("132.187.9.30",2000);
			
			this.is = this.socket.getInputStream();
			this.os = this.socket.getOutputStream();
			
			
			System.out.println("Bytes available: " + is.available()); 
	                      
			
			while(true) {
					
				System.out.println("-------------------------------------------------------");
				
				if(buff.ready()) {
					System.out.println(buff.readLine());			
				}
					
				this.sleep(1000);
				
				if(socket.isConnected() && enableSend) {
					ps.println("cmd_start");
								
				}
				if(!socket.isConnected()) {
					System.out.println("nicht verbunden...");
				}
				if(socket.isClosed() || socket.isOutputShutdown()) {
					System.out.println("Socket down or output down...");
				}
			}

		} catch (Exception e) {

			e.printStackTrace();
			System.out.println("Exception::" + e);
		}
	}
```

*Mein Versuchsablauf:* Hardware(Server) wird eingeschaltet - Die run() zum laufen gebracht. Ich
ziehe den Stecker an der Hardware. => Es fliegt erst mal keine Exception, es wird weiter versucht das 
Kommando cmd_start an den Server zu senden. (Das Kommando dient nur für die Simulation, der 
erwähnten Daten von Außen, darauf, falls möglich, antwortet der Server.)

*Meine Frage:* Was mach ich falsch, was muss ich ändern um mitzubekommen, dass der Stecker 
geflogen ist?

Würd mich freuen, wenn mir wer auf die Sprünge helfen kann! 

Grüße, Ralf


----------



## zeugwart (9. Jul 2012)

Hm,

ist die Fragestellung zu primitiv? Oder weiß mir einfach nur keiner was?

Meine mommentane Lösung sieht so aus:
Im Hintergrund läuft ein Watchdog, wenn 20 Sekunden nichts über die Streams(in & out) lief,
wird die Verbindung mittels socket.close() für tot erklärt. Dann fliegen auch endlich Exceptions auf die man reagieren kann 

Was mir aber sehr pfuschig vorkommt...

LG


----------



## tuxedo (16. Jul 2012)

zeugwart hat gesagt.:


> Hm,
> 
> ist die Fragestellung zu primitiv? Oder weiß mir einfach nur keiner was?
> 
> ...



Hab deinen vorletzten Post nur überflogen. 

Vorrausgesetzt ein Framework wie JBoss Remoting oder MINA kommt für dich nicht in Frage, kannst du das wie folgt lösen:

Kapsel die Netzwerkkommunikation und lasse einen separaten Thread die Schreib/Write Aktionen auf eine Verbindung überwachen (Pseudocode):


```
long lastSent = System.currentTimeMillies();

while(!stopped) {

   wait(writeIdleTime);
   if (System.currentTimeMillies-lastSent >= writeIdleTime) {
      notifyIdleListeners();
   } else {
      lastSent = System.currentTimeMillies();
   }

}
```

Mit jedem write() weckst du den Thread mit "notify()" auf. Der Thread ob er Listener benachrichtigen muss dass die Verbindung schon geraume Zeit brach liegt, oder ob er den Zeitstempel aktualisieren kann.

Dann registrierst du einen Listener der, im Falle eines ausreichend großen Sendeleerlaufs ein kleines Test-Paket über die Leitung schickt. Ist die Verbindung tot, fliegt die eine Exception um die Ohren. Lebt sie noch, kann der Gegenüber die Testnachricht beantworten. Damit erreicht du folgendes:  

a) Du weißt dass die Netzwerk-Verbindung noch lebt
b) Du kannst die RoundTripTime messen und weißt wie schnell die dein Gegenüber antworten kann (ggf. ist auch eine Art Bandbreitenmessung möglich wenn die Nachricht groß genug ist)
c) und kannst daraus ggf. noch ableiten ob dein Gegenüber mit anderen Dingen sehr beschäftigt ist oder nicht. 

Das setzt natürlich vorraus dass du ein Protokoll hast das du entweder um Testnachrichten erweitern, oder eine bestehende Nachricht dafür missbrauchen kannst.

Das Tolle an der Sache ist, dass du die Verbindung nicht unnötig belastest (Testnachrichten gehen erst raus wenn beim Senden ein ausreichend langer Leerlauf entstanden ist) und du gleichzeitig noch weisst dass dein Gegenüber auch abgesehen von der Netzwerkverbindung noch in der Lage ist zu antworten (noch genug CPU, kein Deadlock, etc...).

Und je nachdem wie groß/klein du writeIdleTime wählst, kannst du selbst bestimmen wie schnell du einem Fehler auf der Netzwerkleitung auf die schliche kommen willst. Doch: je schneller desto mehr/häufiger gibt's Traffic.

- Alex


----------



## jamesv (26. Jul 2012)

[OT]
tuxedo, vielen Dank für diese ausführliche Erklärung =)
[/OT]


----------

