Socket.keepAlive()

Hi,

kann mir jemand erklären was die Methode setKeepAlive() macht?
Ich habe eine Socket Verbindung zwischen Smartphone und meinem Rechner erstellt,
die Dauerhaft sein soll, da es sich um einen Chat handelt.

Zunächst habe ich beobachtet, dass nach 60 Sekunden eine SocketTimeOutException bei der read() Methode aufgetreten ist,
wenn in dieser Zeit nichts gesendet wurde.

Eigentlich dachte ich, dass standardmäßig eine unbegrenzte Zeit eingestellt ist beim Socket, und daher nie eine solche Exception geworfen werden würde.

Nachdem ich Socket.setSoTimeout(0) gesetzt habe und Socket.setKeepAlive(true) gesetzt habe, funktioniert nun alles wie es soll
und es kommt zu keiner Exception.

Allerding verstehe ich den Unterschied zwischen Socket.setSoTimeout(0) und Socket.setKeepAlive(true) nicht.
Was macht Socket.setKeepAlive() und wofür wird diese Methode eigentlich verwendet?

deine Formulierung läßt es zwar vermuten, aber ganz eindeutig doch nicht:
hilft es nur wenn du genau BEIDE Änderungen vornimmst?
mit nur der einen oder nur der anderen bleibt es bei dem beschriebenen Problem oder noch anderer Zustand?

KeepAlive scheint (der Literatur nach, leider nicht nach meinem Wissen) erst nach 2 Stunden überhaupt etwas zu tun,
wäre günstig wenn es auch ohne diese Funktion ginge

freilich ist die Variante, dass es nur von dem anderen, setSoTimeout(), abhängt, auch nicht viel erbaulicher,
der Standard sollte bereits 0 sein…

aber ruhig auch mal mit getSoTimeout() abfragen, vielleicht bei SmartPhone doch speziell?
ist es da überhaupt normaler Code oder irgendeine API drüber, die den Socket erstellt und vielleicht modifiziert?
welche Seite der Connection betrifft es? es sind ja sicher beide gleichzeitig im read()-Modus?

wenn Seite A alle 30 sec. etwas sendet, ist dann Seite B zufrieden und bei A irgendwann Exception weil von B nix kommt?
umgedreht wenn B sendet irgendwann bei B der Timeout?
teste die Rollen A und B, haben beide Seiten Probleme oder nur eine?

kannst du den Chat soweit es allgemein geht auf zwei normale Sockets auf zwei PCs
oder auch nur einen PC mit zwei Ports ausprobieren? dort keine Probleme?

StackTrace zur Exception mit Angabe der Klassen/ Methoden mag vielleicht noch Informationen liefern

also laut android-doc ist SO_TIMEOUT default 4102
aber jetzt kommt das witzige : das ist genau so aus dem sun/oracle-java übernommen, auch hier liefert die offizielle DOC diesen wert
es sind zwar etwas mehr als 68min, und ich kann mich nicht erinnern jemals etwas auch nur testweise so lange laufen gelassen zu haben, bringt uns aber erstmal zur erkenntnis : default ist eben doch nicht 0

warum jetzt allerdings die verbindung alle ca. 60 sec abbricht … more code please

Danke für die bisherigen Antworten.

Okay dann kommt hier noch ein wenig Code.
Auf dem Server können verschiedene Buttons gedrückt werden, die
das Smartphone dazu veranlassen eine bestimmte Activity anzuzeigen.
Das Smartphone sendet anschließend eine Bestätigung an den Server, dass
eine neue Activity angezeigt wird.

Wenn ich Socket.setSoTimeout(0) nicht aufrufe und innerhalb von ca 60 Sekunden
kein neues Signal vom Server ans Smarpthone gesendet wird,
dann kann ich ans Smartphone anschließend kein Signal mehr schicken.
Die Exception wird von der read Methode des Servers geworfen.

Wenn ich Socket.setSoTimeout(0) setze dann scheint alles zu funktionieren.
Allerdings bin ich noch dabei ein paar längere und ausführlichere Tests zu machen.

Socket.setKeepAlive(true) kann ich nach den ersten Tests allen Anschein nach wohl
weglassen.

Server Seite auf dem PC

package Model;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class SignalHandler extends Thread
{
	private Socket clientSocket;
	private BufferedReader in;
	private PrintWriter out;
	private MyServer myServer;
	private FacadeModel facadeModel;
	private int groupColor;
	
	public SignalHandler(Socket clientSocket, MyServer myServer, FacadeModel facadeModel, int groupColor)
	{
		this.clientSocket = clientSocket;
		this.myServer = myServer;
		this.facadeModel = facadeModel;
		this.groupColor = groupColor;
		
		try
		{
			this.in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
			this.out = new PrintWriter(this.clientSocket.getOutputStream(), true);
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	
	public void run()
	{
		int active_phase = this.facadeModel.getModelSignal().getActive_phase();
		int groupnumber = this.facadeModel.getStartGUImodel().getGroupNumber();
		this.out.println("StatusInfo:ACTIVE_PHASE:" + active_phase + ":ACTUAL_GROUP_COLOR:" + this.groupColor + ":GROUPNUMBER:" + groupnumber);
		
		boolean run = true; //richtig platzieren, methode erstellen o.ä. momentan nur provisorisch hier
		
		try 
		{
			while(run)
			{
				String eingegebenerText = in.readLine().trim();
				this.myServer.updatePnlAndDlgSystemMessagesOutputTextArea(eingegebenerText);
			} 
		}	
		catch (IOException e)
		{
				e.printStackTrace();
			
		}
		finally
		{
			try
			{
				this.myServer.removeSignalClientSocket(this.clientSocket);
				this.clientSocket.close();
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
}

Android Smartphone

package com.master;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

public class SignalClientThread extends Thread
{
	private String ip;
	private int port;
	private String signal;
	private BufferedReader in;
	private PrintWriter out;
	private Socket clientSocket;
	
	public SignalClientThread(String ip, int port)
	{
		this.ip = ip;
		this.port = port;
	}
	
	
	public void run()
	{		
		try 
		{
			this.clientSocket = new Socket(ip, port);	
			//this.clientSocket.setKeepAlive(true);
			this.clientSocket.setSoTimeout(0);
			this.in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
			this.out = new PrintWriter(this.clientSocket.getOutputStream(), true);
			boolean run = true;
			
			while(run)
			{
				this.signal = this.in.readLine();
				
				if(this.signal.equals("Phase 1"))
				{			 
					 StatusInfo.currentActivity.runOnUiThread(new Runnable() {

	                        @Override
	                        public void run() 
	                        {
	                        	Toast.makeText(StatusInfo.currentActivity, "Phase 1", Toast.LENGTH_SHORT).show();
	                            Intent intent = new Intent(StatusInfo.currentActivity, PhaseOne.class);
	                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	                            StatusInfo.currentActivity.startActivity(intent);
	        					
	        					sendSignal("Farbe: Phase 1 aktiv");
	                        }
	                    });
				}
				else if(this.signal.equals("Phase 2"))
				{
					StatusInfo.currentActivity.runOnUiThread(new Runnable() {

	                        @Override
	                        public void run() 
	                        {
	                        	Toast.makeText(StatusInfo.currentActivity, "Phase 2", Toast.LENGTH_SHORT).show();
	                            Intent intent = new Intent(StatusInfo.currentActivity, PhaseTwo.class);
	                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	                            StatusInfo.currentActivity.startActivity(intent);
	        					
	        					sendSignal("Farbe: Phase 2 aktiv");
	                        }
	                    });
				}
				else if(this.signal.equals("Phase 3"))
				{
					StatusInfo.currentActivity.runOnUiThread(new Runnable() {

	                        @Override
	                        public void run() 
	                        {
	                        	Toast.makeText(StatusInfo.currentActivity, "Phase 3", Toast.LENGTH_SHORT).show();
	                            Intent intent = new Intent(StatusInfo.currentActivity, PhaseThree.class);
	                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	                            StatusInfo.currentActivity.startActivity(intent);
	        					
	        					sendSignal("Farbe: Phase 3 aktiv");
	                        }
	                    });
				}
				else if((this.signal.split(":")[0]).equals("StatusInfo"))
				{
					StatusInfo.ACTIVE_PHASE = Integer.parseInt(this.signal.split(":")[2]);
					StatusInfo.ACTUAL_GROUP_COLOR = Integer.parseInt(this.signal.split(":")[4]);
					StatusInfo.GROUPNUMBER = Integer.parseInt(this.signal.split(":")[6]);
					
	         		StatusInfo.currentActivity.runOnUiThread(new Runnable() {

	                       @Override
	                       public void run() 
	                       {
	                    	   StatusInfo.currentActivity.recreate();
	                       }
	         		 });
				}
			}
		}
		catch (UnknownHostException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		} 
	}
	
	
	public void sendSignal(String signal)
	{
		this.out.print(signal);
		this.out.println();
	}
}

was liefert
getSoTimeout()
vor dem eigenen Setzen?

Was lesenswertes zu diesem Thema:

http://mindprod.com/jgloss/socket.html#DISCONNECT

Aus eigener Erfahrung kann ich sagen: Am besten ein eigenes KeepAlive ins Protokoll mit einbauen. Dann ist man am flexibelsten und kann auch Verbindungsabbrüche bei Inaktivität schneller erkennen.

Gruß
Alex