wait/notify bei Socket

Milo

Bekanntes Mitglied
Hallo,

ich möchte einen rudimentären Client erzeugen, der von einem Server Daten abfragt. In der Insel habe ich gelesen, dass ich Blockierungen abfangen sollte. Wenn ich die dortige Lösung richtig verstehe, wird immer 2sec gewartet auch wenn die Antwort ggf. schon eingetroffen ist. Nun dachte ich, dass ich dieses Problem über wait/notify umgehen kann.

Java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class SocketTest {

	private final String uri;
	private final int port;
	private Socket socket;
	private PrintWriter os;
	private BufferedReader is;
	private final static String AUTHENTIFIKATION = "GET_DATA";
	private StringBuffer response = null;

	public SocketTest(String uri, int port) {
		this.uri  = uri;
		this.port = port;
	}
	
	public boolean open() {
		try {
			socket = new Socket(uri,port);
			os = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
			is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			return true;
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
			
		return false;
	}

	public void getData()  {
		this.response = new StringBuffer();
		try {
			this.sendMessage(AUTHENTIFIKATION);
			
			synchronized (this.response) {
				new Thread() {
					public void run() {
						try {
							readMessage();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}.start();
				// Sollte HIER nicht nach 2sec abgebrochen werden???
				if (this.response == null || this.response.length() == 0)
					this.response.wait(2000);
				
				System.out.println("Antwort " +response);
			}
		} 
		catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	public boolean close() {
		try {
			if (this.is != null)
				this.is.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		try {
			if (this.os != null)
				this.os.close();
			if (this.socket.isClosed())
				this.socket.close();
			
			return true;
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	private void sendMessage(String message) {
		this.os.print(message);
		this.os.flush();
	}
	
	private void readMessage() throws IOException {
		synchronized (response) {
			char[] buffer = new char[1024];
			int read = this.is.read(buffer, 0, buffer.length); // blockiert bis Nachricht empfangen
			this.response.append( new String(buffer, 0, read) );
			this.response.notify();
		 }
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SocketTest socket = new SocketTest("127.0.0.1", 11111);
		socket.open();
		socket.getData();
		socket.close();
	}

}

Ich hatte gehofft, dass durch this.response.wait(2000); max. 2 Sekunden auf den gestarteten Thread gewartet wird und dann in jedem Fall die Methode fortgesetzt wird. Dies ist aber nicht so. Wenn ich die Antwortzeit des Servers mit einem Thread.sleep(10000); verzögere, wartet mein Client die 10sec und bricht nicht, wie gehofft, nach 2sec ab.

Habe ich einen Denkfehler bei der Verwendung von wait/notify?

Gruß Micha

P.S. seit wann gehen eckige Klammern im Code verloren hier im Forum?
 

mfernau

Bekanntes Mitglied
1. Ich kenne den dort erwähnten NIO-Ansatz nicht. Wenn man vermeiden möchte, dass ein Thread endlos auf eine eingehende Nachricht eines Sockets wartet, würde ich (persönliche Meinung) ein Timoutprinzip verwenden. Dafür kann man vor jedem Aufruf von read auf einem Inputstream mit einem TimerTask sicher stellen, dass close() auf dem Socket nach dem Ablauf eines festgelegten Timeouts aufgerufen wird. Ich habe das für meinen Server bei meinem aktuellen Projekt so gelöst:
Java:
	@Override
	public String readLine(long timeout) throws IOException {
		String line = null;
		
		TimerTask tt = null;
		if(timeout != 0) {
			tt = new TimerTask() {
				@Override
				public void run() {
					timoutConnection();
				}
			};
			timer.schedule(tt, timeout);
		}
		
		try {
			line = in.readLine();
			// [...]
			
			if(tt != null) {
				tt.cancel();
				timer.purge();
			}
		} catch (IOException e) {
			/*
			 * Kann auftreten wenn:
			 * a) Ein timeout aufgetreten ist
			 * b) Andere Kommunikationsprobleme auftraten (Client hat Verbindung unterbrochen)
			 */
			if(connectionTimedOut) {
				throw new SocketTimeoutException("Connection timed out");
			} 
			
			throw e;
		}
		
		return line;
	}
Ich kann so mit Angabe eines Timeouts festlegen, wie lange ich maximal auf eine Antwort vom Client warten möchte. Rein vom Prinzip her kann ich an blockierenden Threads nichts schlimmes finden. Sie warten ja nicht aktiv auf Arbeit, sondern schlafen so lange bis Input vom Client herein kommt.

2. Deine Variante funktioniert nicht, weil Deinen Thread in der readMessage() Methode auf dem response-Objekt den Monitor hält.
Was passiert?
a) Du erstellst einen Thread und markierst ihn zum starten. Er wird noch nicht laufen.
b) Jetzt läuft dein main-Thread in das wait() und gibt damit den Monitor im synchronized Block so lange auf.
c) Nun wird dein neu erstellter Thread zum Zuge kommen und in die readMessage()-Methode einlaufen. Dort wird der Thread den Monitor auf das response-Objekt bekommen. Nun läuft dein Thread in das read vom Socket und blockiert dort. Dabei wird er die Sperre aber nicht lösen. Dein main-Thread kann daher nicht aufwachen, weil das response-Objekt so lange noch gesperrt ist, bist dein Thread aus der readMessage heraus kommt. Deine synchronized-Blöcke sind zu groß. Du benötigst sie nur direkt um das wait und das notify. Das genügt.

HTH,
Martin
 

Milo

Bekanntes Mitglied
Hi mfernau,

vielen Dank für Deine Antwort. Wenn ich die synchronized verschiebe, wie Du sagst, funktioniert es wirklich.

Java:
			new Thread() {
				public void run() {
					try {
						readMessage();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}.start();
			synchronized (this.response) {
				if (this.response == null || this.response.length() == 0)
					this.response.wait(2000);
				
				System.out.println("Antwort " +response);
			}

und
Java:
		char[] buffer = new char[1024];
		int read = this.is.read(buffer, 0, buffer.length); // blockiert bis Nachricht empfangen
		this.response.append( new String(buffer, 0, read) );
		synchronized (response) {
			this.response.notify();
		 }

Wo genau mein Denkfehler liegt, konnte ich aber nicht nachvollziehen. ;-)

Wenn ich Deinen Ansatz nutze, wird das Programm nicht mehr beendet. In der main-Methode wird System.out.println("Ende!") noch ausgeführt aber das Programm danach nicht geschlossen. Warum nicht, wo liegt das Problem?

Gruß Micha

Java:
package socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Timer;
import java.util.TimerTask;

public class SocketClient {

	private final String uri;
	private final int port;
	private Socket socket;
	private PrintWriter os;
	private BufferedReader is;
	private final static String AUTHENTIFIKATION = "GET_DATA";

	// [url]http://www.java-forum.org/java-basics-anfaenger-themen/154369-wait-notify-socket.html[/url]
	public SocketClient(String uri, int port) {
		this.uri  = uri;
		this.port = port;
	}
	
	public boolean open() {
		try {
			this.socket = new Socket(this.uri, this.port);
			this.os     = new PrintWriter(new OutputStreamWriter(this.socket.getOutputStream()));
			this.is     = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
			return true;
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
			
		return false;
	}

	public void getData()  {
		String response = null;
		try {
			if (this.socket != null && this.socket.isConnected()) {
				this.sendMessage(AUTHENTIFIKATION);
				response = this.readMessage(2000);
			}
		} 
		catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("Antwort " +response);
	}

	public boolean close() {
		try {
			this.socket.close();
			this.os.close();
			this.is.close();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	private void sendMessage(String message) {
		this.os.print(message);
		this.os.flush();
	}
	
	private String readMessage(long timeout) throws IOException {
		String line = null;
		Timer timer = new Timer();
		
		TimerTask unlockTask = null;
		if(timeout != 0) {
			unlockTask = new TimerTask() {
				@Override
				public void run() {
					close();
				}
			};
			timer.schedule(unlockTask, timeout);
		}
		
		char[] buffer = new char[1024];
		int read = this.is.read(buffer, 0, buffer.length); // blockiert bis Nachricht empfangen
		line = new String(buffer, 0, read);
			
		if(unlockTask != null) {
			unlockTask.cancel();
			timer.purge();
		}

		return line;
	}	
	
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {

		SocketClient socket = new SocketClient("127.0.0.1", 11111);
		socket.open();
		socket.getData();
		socket.close();

		System.out.println("ENDE!");
	}

}
 

mfernau

Bekanntes Mitglied
Hallo!

Wenn ich Deinen Ansatz nutze, wird das Programm nicht mehr beendet. In der main-Methode wird System.out.println("Ende!") noch ausgeführt aber das Programm danach nicht geschlossen. Warum nicht, wo liegt das Problem?

Den Codeausschnitt den ich Dir mit dem Timer gepostet habe war nicht komplett. Du musst einen erstellten Timer noch canceln sonst läuft der mit dem Timer assoziiert Thread weiter.
Schau Dir das mit dem Timer hier mal an: Galileo Computing :: Java ist auch eine Insel – 14.7 Zeitgesteuerte Abläufe

Was konkret bei Dir fehlt ist ein
Code:
timer.cancel();
nachdem alles abgeschlossen ist.
Der Korrektheit würde ich den Timer auch nicht in der read-Methode erstellen, sondern im Konstruktor. Denn der Timer wird wiederverwendet, während die TimerTasks wegwerf-Objekte sind.

Schöne Grüße
Martin
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
O Threads - Synchronize(), join(), wait(), notify(), yield() Java Basics - Anfänger-Themen 6
ralfb1105 Frage zu Thread Synchronisation mit wait() und notify() Java Basics - Anfänger-Themen 3
M notify und wait Java Basics - Anfänger-Themen 1
D Stack-Objekt - LIFO - wait(); notify(); Java Basics - Anfänger-Themen 0
D Probleme mit wait(), notify() Java Basics - Anfänger-Themen 0
Luk10 Monitor: wait() und notify() Java Basics - Anfänger-Themen 8
S Threads: wait() und notify() Java Basics - Anfänger-Themen 11
S bin zu blöd für threads - wait, notify, synchronized Java Basics - Anfänger-Themen 11
B Problem: wait() -> notify() Java Basics - Anfänger-Themen 4
M Threads, wait() und notify() Java Basics - Anfänger-Themen 10
G Threads steuern mit wait und notify Java Basics - Anfänger-Themen 2
P wait und notify oder wie soll ich es lösen Java Basics - Anfänger-Themen 2
I Exception bei Button mit wait() und notifyAll() Java Basics - Anfänger-Themen 3
M Threads synchronized und wait Java Basics - Anfänger-Themen 2
BlueFox Greenfoot wait() Java Basics - Anfänger-Themen 10
A wait() problem Java Basics - Anfänger-Themen 3
G wait()-Mehtode Java Basics - Anfänger-Themen 13
T meinThread.wait(); wirft immer Exeption & hat kein Effekt Java Basics - Anfänger-Themen 15
R wait() in synchronized - Block oder nicht? Java Basics - Anfänger-Themen 4
M wait() sleep() geht nicht wirklich Java Basics - Anfänger-Themen 3
vogella *Gelöst *Im Programm warten (wait()) Java Basics - Anfänger-Themen 2
D Wait und Image Java Basics - Anfänger-Themen 3
U wait Java Basics - Anfänger-Themen 2
O Problem bei der Synchronisierung von Threads (wait&notif Java Basics - Anfänger-Themen 4
C java.util.Timer und wait() oder so was Java Basics - Anfänger-Themen 3
I Threads Multithreading, Producer/Consumer, notify() Java Basics - Anfänger-Themen 6
kilopack15 Verständnisfrage zur Verwendung von notify() bei Threads Java Basics - Anfänger-Themen 2
M Threads notify/notifyAll Philosophen-Problem Java Basics - Anfänger-Themen 14
M Threads notify Java Basics - Anfänger-Themen 6
T Alle Threads .notify() Java Basics - Anfänger-Themen 13
M lock notify synchronisation Java Basics - Anfänger-Themen 8
S Problem mit notify() Java Basics - Anfänger-Themen 4
M Warum kann man dem Thread kein notify senden? Java Basics - Anfänger-Themen 15
izoards Socket Kommunikation Java Basics - Anfänger-Themen 16
Nina Pohl Ein Vorgang bezog sich auf ein Objekt, das kein Socket ist Java Basics - Anfänger-Themen 6
G Socket Verbindung aufbauen Java Basics - Anfänger-Themen 11
S Bilder über Socket Senden Java Basics - Anfänger-Themen 1
S Asynchrone Socket-Abfragen Java Basics - Anfänger-Themen 5
Meeresgott OOP Socket Verbindung richtig Kapseln Java Basics - Anfänger-Themen 0
O Socket by reference übergeben Java Basics - Anfänger-Themen 0
J Socket schließen - Ist eine SocketException unumgänglich? Java Basics - Anfänger-Themen 4
D Socket ---> Server Socket worauf muss ich achten? Java Basics - Anfänger-Themen 2
N Socket-Programmierung Java Basics - Anfänger-Themen 4
B Input/Output Socket I/O - outputStream.write(-1) Java Basics - Anfänger-Themen 2
B Socket OutputStream Java Basics - Anfänger-Themen 17
B Socket Kommunikation in beide Richtungen Java Basics - Anfänger-Themen 12
B Socket, args Java Basics - Anfänger-Themen 22
L Socket in JTextArea Java Basics - Anfänger-Themen 9
T Input/Output Zwei InputStreams von einem Socket Java Basics - Anfänger-Themen 2
B Socket Problem Java Basics - Anfänger-Themen 3
T socket.close aber verbindung besteht noch Java Basics - Anfänger-Themen 4
F Buffered Image über Socket versenden Java Basics - Anfänger-Themen 6
E Socket InputStream "terminiert" nicht Java Basics - Anfänger-Themen 4
B Threads Interrupt während Socket.read()? Java Basics - Anfänger-Themen 3
M Versand von Nachrichten via Socket (Delay) Java Basics - Anfänger-Themen 21
F socket-problem Java Basics - Anfänger-Themen 6
E Input/Output Socket bekommt keine Verbindung bei funktionierendem Fremdziel Java Basics - Anfänger-Themen 2
E Socket (Client) dauerhaft aktiv? Java Basics - Anfänger-Themen 9
D Java - Socket - Datenübertragung Java Basics - Anfänger-Themen 18
E Input/Output einfachen Socket für XML-Anfragen bauen Java Basics - Anfänger-Themen 13
R Cannot find a free socket for the debugger Java Basics - Anfänger-Themen 6
F Socket Kommunikation Java Basics - Anfänger-Themen 4
M "Connection reset" gbxRemote Socket Java Basics - Anfänger-Themen 9
N Files mit Byte an Socket versenden Java Basics - Anfänger-Themen 2
L FTP per Socket Java Basics - Anfänger-Themen 2
M Audio Stream läuft auf :connection abort: socket write error Java Basics - Anfänger-Themen 2
J Socket - BufferedReader lese Problem Java Basics - Anfänger-Themen 2
M Socket Server Java Basics - Anfänger-Themen 9
N Socket Problem? Java Basics - Anfänger-Themen 9
G Socket erstellen dauert sehr lange. Java Basics - Anfänger-Themen 4
H Java Socket Java Basics - Anfänger-Themen 14
A XML Daten über Socket Java Basics - Anfänger-Themen 3
I Allgemeine fragen zu Socket server Java Basics - Anfänger-Themen 6
C Socket Programmierung Java Java Basics - Anfänger-Themen 4
F Socket Instanz auf Klasse welche von Socket erbt zuweisen Java Basics - Anfänger-Themen 3
ven000m Wieso antwortet mein Server nicht mehr (Socket Anwendung) Java Basics - Anfänger-Themen 2
J Daten von einem (char*)Socket einlesen. Java Basics - Anfänger-Themen 3
S Java Socket Java Basics - Anfänger-Themen 3
K Frage zu SdtOut streams bzw. Socket Programmierung Java Basics - Anfänger-Themen 3
M HTTP-Anfragen und Socket Java Basics - Anfänger-Themen 2
A von Socket-Stream lesen Java Basics - Anfänger-Themen 4
M Ändern einer Socket-Eigenscheft aus einem modalen Dialog? Java Basics - Anfänger-Themen 6

Ähnliche Java Themen

Neue Themen


Oben