# Wahrnehmen, dass ServerSocket geschlossen wurde



## max5432 (22. Jan 2010)

Hallo

Wie kann ich auf der Client-Seite merken, dass der ServerSocket geschlossen wurde? Kann ich irgendwie den Socket (Client-Socket) testen (isConnected / isBound / usw.), um dies festzustellen? Ich habe mit isConnected, isBound usw. versucht, jedoch ohne Erfolg. 

Hinweis:
Verbindung wird aufgebaut und die Streams geholt. Jedoch wird das Schreiben und das Lesen nur auf Aufforderung durchgeführt. So bin ich auf der Client-Seite nicht am Warten 


```
String input = bReader.readLine();
```

oder so was ähnliches. 

Hat jemand einen guten Tipp? Ich komme nicht weiter, und es ist recht spät (oder früh, wie man es nimmt ;( ) 

Danke.


----------



## Empire Phoenix (22. Jan 2010)

Du könntest erstens die read ineinen eigenen Thread verlagern dann hängt nicht das Programm falls keine daten zum lesen verfügbar sind., Zudem ein einfacher test ob ne Connection noch aktiv ist, schick einen code den der server antwortet (aka ping,pong)


----------



## max5432 (22. Jan 2010)

Danke für die Antwort.

Ein "ping" wäre sicher möglich, finde ich aber etwas unschön.  

Und wegen Auslagerung von read-Aktionen in einen eigenen Thread ... 

Ich habe eine GUI auf der Client-Seite, die allerdings die ganze Kommunikation mit dem Server über eine Proxy-Komponente abwickelt. Die Nachrichten,die zu übertragen sind, sind kurz und verursachen an sich keine Verzögerung in der GUI-Anzeige. Wenn ich eine Aktion durchführen möchte, wird entsprechende Methode auf der Proxy-Komponente aufgerufen, die ihrerseits eine passende Nachricht sendet und direkt danach die Antwort liest. Danach steht die Socketverbindung leer, bis die nächste Aktion wierder veranlasst wird. Ich sehe den gewinn durch einen separaten read-Thread nicht ganz: sicher könnte ich die GUI problemlos auch dann anzeigen, wenn sich das Lesen "aufhängen" sollte, jedoch handelt es sich um eine synchrone Kommunikation, bei der ich auf die Antwort des Servers angewiesen bin. Also, wenn die Antwort nicht kommt, ist das schon einmal nicht gut. Oder, hast du es anders gemeint?

Ich möchte verhindern, dass der Client eine Aktion veranlasst und erst beim Senden der Anfrage erfährt, dass die Verbindung nicht mehr steht (wie dies jetzt der Fall ist): die unnötige Eingabe von Daten könnte man sich sparen. Der Client verabschiedet sich "anständig" beim Server, wenn er beendet wird. Der Server sollte dies auch tun, damit ich den Client-Benutzer informieren kann, dass die Verbindung nicht mehr da ist. Er kann ein "Tschüss" schon senden, nun ist auf der Client-Seite niemand, der es entgegennimmt. 

Ich habe versucht, mit einem "WatchDog"-Thread, der den InputStream des Sockets erhält und den Abschied des Servers "hören" kann. Nun hat das aber nicht so gut geklappt, wie ich wollte. Sobald ein Thread den Inhalt des Streams gelesen hat, bleibt der andere "hängen". Und, dem WatchDog zu sagen, dass die Proxy-Komponenten an sich auf die Antwort waretet und er da nicht "rein funken" soll, ist mir nich so richtig gelungen. Habe zwar mit dem PushbackInputStream versucht, die Nachricht, die nicht für WatchDog war, in den InputStream zurück zu schreiben (unread-Methode), aber bin auch nicht viel weiter gekommen. Ab und zu hat es schön funktioniert, aber nur ab und zu.


----------



## MQue (22. Jan 2010)

Also ich würde 

Socket#setSoTimeout(X) setzen und dann mit Socket#isConnected() vor dem Senden abfragen, ob dieser noch verbunden ist, das müsste funktionieren.


----------



## max5432 (22. Jan 2010)

MQue hat gesagt.:


> Also ich würde
> 
> Socket#setSoTimeout(X) setzen und dann mit Socket#isConnected() vor dem Senden abfragen, ob dieser noch verbunden ist, das müsste funktionieren.



Habe es versucht:

Proxy:


```
/* Socket erzeugen */
clientSocket = new Socket(hostIp, servicePort);

/* Timeout setzen */
clientSocket.setSoTimeout(3000); 

// ...

/* Methode zum Prüfen, ob Socket immer noch verbunden ist */
public boolean isConnected(){
    return clientSocket.isConnected(); 
}
```

In der GUI frage ich jetzt ab (bevor die Eingabe von Daten in einem Dialog vorgenommen wird), ob die Verbindung steht: 


```
// Methode 'actionPerformed' ... 

boolean connected = proxy.isConntected(); 

if (connected) {
    // Daten eingeben 

    // Passende Methode auf der Proxy-Komponenten aufrufen und auf die Antwort warten 
 

}
else {
    // Passende Meldung mit JOptionPane anzeigen ...

}
```

Die Verbindung wird hergestellt und kurz danach wieder beendet vom Server. Ich warte sicherheitshalber länger als 3 Sekunden!!! bevor ich die Aktion starte, die *proxy.isConnected* aufruft. Leifer bekomme ich auch hier "true", obwohl der Server schon längst nicht mehr 'online' ist. 

Oder, habe ich was falsch verstanden?

Und, der Server ist sicher nicht mehr online: Wenn ich einen neuen Client starte und Verbindung herstellen versuche, klappt es nicht mehr.


----------



## MQue (22. Jan 2010)

Probiers mal so:


```
private boolean isConnected() {
        if(socket != null && inputStream != null && outputStream != null)
            return socket.isConnected();
        return false;
        }
```


----------



## tuxedo (22. Jan 2010)

isCOnnected() prüft intern nur ein Flag ab. Soweit ich das gesehen habe wird das nicht durch einen "verbindungsverlust" rückgesetzt, sondern nur, wenn du in den Fehler reinläufst.

Die einzig wahre Möglichkeit rauszufinden ob die Verbindung noch funktioniert ist ein PingPong auf Protokoll-Eben zu betreiben. 

Ansonsten bleibt dir nur noch 
	
	
	
	





```
setKeepAlive()
```
 auf dem Socket zu setzen und zu hoffen, dass der Verbindungsabbruch auf Zeitnah erkannt wird (was nicht garantiert wird).

Siehe zu dem Thema auch: socket : Java Glossary

Gruß
Alex


----------



## max5432 (22. Jan 2010)

MQue hat gesagt.:


> Probiers mal so:
> 
> 
> ```
> ...



Danke. 

Habe es getestet: leider funktioniert dies auch nicht. 

Nun, ich habe es jetzt wie folgt "gelöst": 
Bevor ich eine Aktion starte, sende ich ein "ping" zum Server, um zu erfahren, ob er noch online ist. So kann ich zumindest die nutzlose Eingabe von Daten verhindern, wenn die Verbindung nicht mehr steht.


----------



## max5432 (22. Jan 2010)

@Alex:

Habe es gelesen. Mein Wunsch wird halt ein "frommer Wunsch" bleiben 

Vielen Dank.


----------



## tuxedo (22. Jan 2010)

max5432 hat gesagt.:


> Nun, ich habe es jetzt wie folgt "gelöst":
> Bevor ich eine Aktion starte, sende ich ein "ping" zum Server, um zu erfahren, ob er noch online ist. So kann ich zumindest die nutzlose Eingabe von Daten verhindern, wenn die Verbindung nicht mehr steht.



Wieso so "kompliziert"?

Wenn du eine Aktion startest, dann a) klappt das oder b) kommt eine Exception. Das reicht doch?

Wenn du jetzt vorher noch ein Ping Paket schickst, dann macht das das gleiche in grün: Es wird geschaut ob's klappt oder ob eine Exception kommt.

PingPong macht eigentlich nur dann Sinn, wenn die Verbindung "herum idle't" und du möglichst zeitnah mitkriegen willst ob die Verbindung tot ist. Wenn du eh immer wieder Daten sendest, dann brauchst du kein PingPong.

- Alex


----------



## FArt (22. Jan 2010)

Ping-Pong (oder nur Ping, je nach Kommunikationsart) ist ausreichend und das Mittel der Wahl.


----------



## max5432 (22. Jan 2010)

tuxedo hat gesagt.:


> Wieso so "kompliziert"?
> 
> Wenn du eine Aktion startest, dann a) klappt das oder b) kommt eine Exception. Das reicht doch?
> 
> ...




Ich habe einen Fall, wo der Benutzer relativ viel Daten in einem Dialog eingeben muss. Bevor er dies macht, möchte ich sicher sein, dass die Verbindung steht, damit er die Eingabe nicht umsonst tätigt (falls z. B. der Server heruntergefahren wurde). Also, er merkt, dass die Verbindung nicht steht und stellt zuerst die Verbindung her: wenn es klappt, macht er weiter, sonnst gibt er auf. Eine andere Variante wäre sicher die eingegeben Daten zu retten und die nach dem neuen Verbindungsaufbau wieder zu senden. Dies scheint mir aber komplizierter zu sein. Ausserdem (wie schon geschrieben) kann es sein, dass der Server gar nicht läuft (heruntergefahren). In diesem Fall wird sich die Freude des Benutzer über die umsonst eingegebenen Daten zeimlich "im Rahmen" halten. :bahnhof:


----------



## tuxedo (22. Jan 2010)

Aaaalso. Du wirst ja erst den Dialog mit "weiter" oder "okay" abschließen bevor du anfängst zu senden.

Ergo hast du ein Sammelsurium von Variablen/Daten die gesendet werden müssen.

Die gehen mit dem Senden ja nicht gleich verloren. Das senden umschließt du mit einem Try/Catch und probierst im Catch den die Verbindung wiederherzustellen und die Daten (die Variablen sind ja noch da) nochmal zu senden.

Den Ping voran schieben macht die Sache nicht anders. Das ist doch das gleiche in grün?! Was ist wenn der ping funktioniert und dann das senden der Daten fehl schlägt? Auf den Ping kannst du dich nicht allein verlassen.

- Alex


----------



## max5432 (23. Jan 2010)

> Was ist wenn der ping funktioniert und dann das senden der Daten fehl schlägt? Auf den Ping kannst du dich nicht allein verlassen.



Das stimmt. Eine gewisse Unsicherheit bleibt halt immer. 

Ich habe auf die automatische Weiderherstellung der Verbindung zur Zeit verzichtet. Jedoch finde ich diene Überlegung richtig und werde versuchen, meinen Code entsprechend anzupassen. 

Gruss,

max5432


----------



## tuxedo (23. Jan 2010)

max5432 hat gesagt.:


> Das stimmt. Eine gewisse Unsicherheit bleibt halt immer.



Mit einem try/catch und entsprechender Reaktion bleibt keine Unsicherheit.


----------

