# Keep Alive bei TCP/IP



## luk123 (29. Jan 2013)

Hallo,

ich muss ein Keep Alive für eine TCP/IP Verbindung realisieren. Das heißt ich muss überprüfen ob die Gegenstelle noch nach Nachrichten horcht. Problem ist das die Verbindung noch aktiv sein kann. Weiteres Problem ist das ich nicht davon ausgehen kann das die Gegenstelle auf ein 'Testtelegramm' antwortet. Das heißt ich muss irgendwie überprüfen ob Nachrichten entgegengenommen wurden.


```
PrintWriter outPrintWriter = new PrintWriter(this.socket.getOutputStream(),
					false);

outPrintWriter.print(messageText);
outPrintWriter.flush();

outPrintWriter.checkError();
```

checkError liefert immer false zurück solange die Verbindung an sich noch aktiv ist. Hänge ich jetzt auf der Gegenstelle in einem Sleep fest wird aber trotzdem false zurück geliefert. Im falle eines Verbindungsabbruches, also der Socket wird geschlossen, wird true zurück geliefert....aber das bekommen ich ja auch so mit, durch eine Exception die geworfen wird.

Kann mir jemand bei meinem Problem helfen? Ich hoffe ich habs einigermaßen verständlich erklärt!

LG


----------



## xote (29. Jan 2013)

Soweit ich weiss, kann man das ACK Flag mittels 
	
	
	
	





```
Socket.setKeepAlive(boolean on)
```
 setzen. Wirft bei Fehlern eine Exception, aber genaueres sollte in der API zu finden sein.


----------



## luk123 (29. Jan 2013)

Das hilft leider auch nicht...


----------



## tröööt (29. Jan 2013)

ähm ... KeepAlive ist eigentlich etwas der anwendungs-ebene ... nicht der transport-ebene ...

es ist aufgabe der software zu prüfen ob die gegenseite noch aktiv ist ... TCP stellt hier lediglich den kommunikations-kanal bereit ... und wenn die gegenseite so schlampig geschrieben ist das diese dem gegenüber nicht eindeutig mitteilt wann die verbindung getrennt werden kann ist das wohl kaum dein problem ... sondern ein protokoll-fehler ... bzw falls das protokoll sowas vorschreibt ein implementierungs-fehler ... das hat nichts mit TCP zu tun ... sondern mit deiner gegenstelle ...

wenn der entwickler dessen also mist gebaut hat gibts für dich keinen weg "sauber" an diese info zu kommen .. vor allem dann nicht wenn auf "ping"-pakete nicht reagiert wird ...


----------



## Bernd Hohmann (29. Jan 2013)

xote hat gesagt.:


> Soweit ich weiss, kann man das ACK Flag mittels
> 
> 
> 
> ...



Die API gibt nicht viel her, denn das hängt alles von der Konfiguration des TCP/IP-Stacks des OS ab.

Grundsätzlich läuft das so: Wenn das Flag gesetzt wird und _tcp_keepalive_time_ Sekunden keine Daten über den Socket geflossen sind werden danach zukünftig im Abstand von _tcp_keepalive_intvl_ Sekunden automatisch Keepalive-Pakete gesendet. Schlägt das _tcp_keepalive_probes_ mal fehl, wird die Connection als "tot" erklärt.

Blöderweise sind die genannten Parameter nicht von Java aus erreichbar und es ist auch nicht bekannt, auf welche Werte die eventuell von der Runtime gestellt werden. 

Die Presets eines hundsgewöhnlichen Stacks sind eher konservativ und nicht zu gebrauchen:

tcp_keepalive_time = 7200 sek (2 Stunden)
tcp_keepalive_intv = 75 sek 
tcp_keepalive_probes = 9

Bernd


----------



## Bernd Hohmann (29. Jan 2013)

luk123 hat gesagt.:


> checkError liefert immer false zurück solange die Verbindung an sich noch aktiv ist. Hänge ich jetzt auf der Gegenstelle in einem Sleep fest wird aber trotzdem false zurück geliefert.



Das ist auch klar, denn der Socket lebt ja noch und wärend die Gegenseite schläft laufen die Daten halt dort in einen Puffer rein (zum Glück ist das so, denn andernfalls müssten meine Applikationen hier gehetzt die Daten Bitweise wegpollen damit es nicht zum Timeout kommt).

Um also auf der Anwendungsschicht festzustellen, ob die Anwendung noch lebt geht nur zuverlässig über ein Ping/Pong auf Anwendungsebene.

Ich hab Dir mal was gebastelt: Das lauffähige Snippent eröffnet einen ServerSocket, wartet auf eine Connection (die aus dem Thread kommt) und schiebt viele Daten rein. Obwohl es keinen Abnehmer auf der Serverseite gibt, flutschen die Daten durch und es gibt nirgendwo eine Exception.


```
import java.io.PrintWriter;
import java.net.*;

public class SocketTimeouts extends Thread {

	public static void main(String[] args) {
		try {
			new SocketTimeouts().start();
			ServerSocket ssok = new ServerSocket(4711, 1, InetAddress.getLocalHost());
			System.out.println("main() wait for incoming connection");
			Socket sok = ssok.accept();
			System.out.println("main() got connection, ideling");
			tunix(5000);
			System.out.println("main() closing connection");
			sok.close();
			ssok.close();
		} catch (Throwable t) {
			System.out.println("main() panic: " + t.toString());
		}

	}

	@Override
	public void run() {
		try {
			System.out.println("run() start");
			tunix(500);
			Socket sokRun = new Socket(InetAddress.getLocalHost(), 4711);
			PrintWriter pw = new PrintWriter(sokRun.getOutputStream());
			System.out.println("run() connected");
			for (int i = 0; i < 1000; i++) {
				System.out.println("run() sending part " + i);
				for (int k = 0; k < 1000; k++)
					pw.println("0123456789abcdefghijklmnopqrstuvwxyz");

			}
			sokRun.close();
			System.out.println("run() leave");

		} catch (Throwable t) {
			System.out.println("run() panic: " + t.toString());
		}

	}

	private static void tunix(long l) {
		try {
			Thread.sleep(l);
		} catch (InterruptedException e) {
			System.out.println("tunix(): " + e);
		}

	}

}
```


----------

