[MW] Aufgabe 3

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

[MW] Aufgabe 3
Hi,
ich hab mal wieder keine Ahnung, wie ich in der 3. Aufgabe weitermachen soll. Ich glaube die Client-Request-Seite jetzt einigermaßen fertig zu haben, vom Rest hab ich nich so recht nen Plan, wie das überhaupt aussehen soll. Jetzt hab ich mir nochmal das mitgelieferte Testprogramm und die generierten Account-Stub/Skel-Klassen angeschaut, aber schlau bin ich daraus nicht geworden. Wie es aussieht, wird AccountImpl_Skel überhaupt nicht verwendet. Wie soll dieses Beispiel so denn jemals funktionieren?

Wie packt man eigentlich so ein Objekt aus einem empfangenen DatagramPacket wieder aus? Das Einpacken stand auf den Folien irgendwo, kapiert hab ich diese imo etwas chaotische Rumstreamerei und -packerei aber nicht, kann mir den Rückweg also auch nicht selber zusammenbauen. Muss dieses Auspacken dann in Request.process()?

Warum muss ich zum Senden eines UDP-Pakets eine Portnummer angeben? War das nicht immer so, dass sich das System zum Senden selbst einen Port ausgesucht hat? Und welchen Zweck hat das bei UDP überhaupt noch? Da könnten ja praktisch alle vom selben Port aus senden, ist ohne eine Verbindung ja eh nur Formalismus. Und der Server schickt seine Antwort einfach genau an die Client-Adresse zurück, die ja wohl hoffentlich übertragen wird.

Und wo ich am Ende diesen Receiver mit reinstopfen muss, kann ich mir auch irgendwie nicht so recht vorstellen… Wie soll mein ORB denn überhaupt irgendwelche Methodenaufrufe mit korrekten Parametern und Rückgaben vermitteln können, wenn er die Objekte gar nicht kennt? (Im ORB-Projekt sind jedenfalls keine Nutzobjekte vorgesehen.)

Warum fangen wir in der MW-Übung eigentlich sofort mit dem schwierigsten Kapitel an? Ich mein, üblicherweise lerne ich eine neue Technologie kennen, indem ich fertige Lösungen anwende und damit experimentiere. Wenn ich weiß, was die können und wie die sich verhalten, kann ich schauen, warum das so ist, und an den Internals spielen. Wenn ich das gemacht hab, dann kann ich mir so ein nicht triviales System selber schreiben. Aber doch nicht gleich am Anfang! Kein Nichtschwimmer wird in der zweiten Stunde des Schwimmkurses gleich Unterwasserakrobatik machen.


[unqualifizierterkommentar]
vielleicht ist das ja die nichtschwimmer übung zum aufwärmen? :wink:
[/unqualifizierterkommentar]


Hi,

nur mal kurz eine Antwort, mehr wohl lieber im Real Life, bevor ich hier Romane schreibe…

Den musst du in deinem Broker verwenden!

Das Auspacken geht genauso wie das Einpacken, nur mit s/Output/Input/g. Und das Auspacken passiert dort, wo empfangen wird: Beim Server also im Broker und beim Client (in Aufgabe d) im Receiver.

Das ist gerade der Witz: Beim Senden wird eine beliebige Source-Portnummer herausgesucht, zurueckgesendet wird aber an eine bekannte Nummer, an der der Receiver lauscht. Tip: mach erstmal nur bis zur c), da kannst du dann jedem Thread auch einzeln sein Ergebnis zurueckschicken, dann hast du auch erstmal keine grossen Synchronisationsprobleme, die dich Stunden kosten :[…

Die Frage verstehe ich nicht.

Gruesse,
-Steppenwolf


In Request.process() muss man ja anhand der Objekt-ID das passende Objekt aus dem ObjectStore rausholen. Nur leider verfügt der Request-Kontext über keinen Zugang zum ObjectStore des Brokers. Wie komm ich jetzt also an das Teil ran? Das Request-Objekt wird auf dem Client erstellt, da kann es also nicht reingelangen. Der ClientContext stammt ebenfalls vom Client und ist dafür ungeeignet. Der Broker-Kontext rührt das Request-Objekt nichtmal an, also auch hier kein Schnittpunkt. Ist da ein Fehler im Konzept?


Mein Request hat eine Init methode, die vom Broker aufgerufen wird und damit das request mit dem ObjectStore versorgt. Um genauer zu sein, ich frage im Broker zuerst das Request Objekt nach seiner OID und versorge es dann per init mit dem passenden Skeleton damit sich das request darum nicht kümmern muss. Das process() arbeitet dann auf diesem Sekeleton.


Danke, das erscheint logisch.

Aber Leute, Java nervt langsam so richtig. In Request.send() soll “this” über einen Stream übertragen werden. Und an genau dieser Stelle wird eine NotSerializableException geworfen. “this” hat im ersten Debuglauf auf ein “AccountImpl_Stub” gezeigt, irgendwie muss Java da über irgendwas ausgerutscht sein - paar Variablen verwechselt, kann ja mal vorkommen. Ab dem nächsten Debuglauf zeigt es auf ein “Request”. Aber auch “class Request implements Serializable” behebt diese Störung nicht. Wie kann ich also ein Objekt serialisierbar machen, wenn nicht so?


Naja prinzipiell muss alles serialisierbar sein, was in dem Objekt drinhängt. Sind da evtl irgendwelche Kontexte drin, die nicht serialisiert werden können?


Jaaaa natürlich…


Du kannst auch Objekte mit transient markieren, die dann nicht serialisiert werden. Praktisch fuer Objekte, die das nicht sollen oder sogar koennen (!), wie z. B. Sockets.


Und wie soll dieser Receiver jetzt funktionieren? Die Vorgabe ist praktisch leer, die Übungsfolie enthält zu wenig Informationen, eine Java-Online-Referenz für wait() hab ich nicht gefunden und die Eclipse-Hilfe unter Windows verweigert bei dieser Funktion den Dienst (Seite kann nicht geladen werden), unter MacOS hab ich in Eclipse gar keine Hilfe.

Request.send() versendet sich selber und macht dann “wait()”. Request.process() sendet den Rückgabewert zurück und ist dann fertig. Wie bekomme ich den Rückgabewert dann in den Kontext der noch wartenden send()-Funktion auf dem Client rein, so dass die das Ergebnis zurückgeben kann und der Aufruf abgeschlossen wird?


Mein Receiver startet im Konstruktor einen neuen Thread, der auf dem Client-UDP Port Pakete entgegennimmt und die in Result Objekte umwandelt. Außerdem hat der Thread eine Receiver Referenz. Der Thread gibt dann das empfangene Result Objekt an den Receiver zurück.
Der Receiver hat eine Hashtable in der die Request Objekte mit einer eindeutigen ID vermerkt werden. Die Result Objekte haben die ID zum passenden Request.
Bei einem Request blockiert sich das Request Obkekt selbst. Deblockiert wird es dann wieder vom Receiver, der das Result Objekt in das passende Request packt. Das Request kann dann von send() zurückkehren und das erhaltene Result zurückgeben.


Aha, is das alles kompliziert.

Nun ja, nach etwas Rumgehacke bekomm ich jetzt diese Exception im Client zu sehen:
IllegalMonitorStateException: current thread not owner
in der Zeile:
Request.send(): wait();

Was bedeutet das?


Das bedeutet (glaube ich hier so offline beurteilen zu koennen), dass du ein wait() machst, ohne in einem Monitor zu sein. Aber jetzt das Ganze nicht einfach in ein synchronized packen, sondern ueberlegen, was synchronisiert werden muss und wo!

BTW die Doku zu wait() etc. findest du bei der Klasse Object, da du jedes Objekt als Monitor hernehmen kannst…


Was ist ein Monitor? Mein Bildschirm wird’s wohl nicht sein, da pass ich net rein…


Hm, wie auch immer, ich hab jetzt die Methode mit dem wait() drin synchronized gemacht. Die Exception lässt sich jetzt nicht mehr blicken, aber der Client tut auch nichts sinnvolles mehr, nachdem die erste Anfrage auf dem Server bearbeitet wurde. Bin noch am Suchen…


Ich blick da net durch. Auf dem Server wird das UDP-Paket an 127.0.0.1:38031 losgeschickt, im Client, der auf Port 38031 hört, kommt nie etwas an. DatagramSocket.receive() blockiert unendlich. Warum?
(Eclipse 3.1/Java 1.5/Max OS X 10.4.3)


Also bei mir tut das:

Server:

....
DatagramSocket socket = new DatagramSocket();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream obj_out = new ObjectOutputStream(stream);
obj_out.writeObject(result);
byte[] buffer = stream.toByteArray();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, 
					serverContext.getClientAdress(), serverContext.getClientPort());
socket.send(packet);

Client:

DatagramSocket socket = new DatagramSocket(port);
			while(true) try{
				if(isInterrupted())
					break; //SHUTDOWN befohlen
				byte[] buf = new byte[1024];
				DatagramPacket packet = new DatagramPacket(buf, buf.length);
				socket.receive(packet);
				...
				}

Mann, da muss man erstmal dahinter kommen, wie man in Eclipse 2 Programme gleichzeitig debuggt, ohne dass was verloren geht. Scheinbar kommt das Paket jetzt wohl an, und muss wohl auch in einem brauchbaren Zustand sein, weshalb jetzt weiterer Code ausgeführt wird: Der Receiver soll jetzt den wartenden Request aufwecken. Das tut er mit request.notify(). Da kommt aber wieder diese Exception von eben bei raus. Keine Ahnung warum. Kann mir jemand erklären, wie ich wait() und notify() richtig verwende, um eine andere wartende Funktion gezielt von außen aufzuwecken? Nur notify() (an this anstatt des Request-Objekts) aufzurufen blockert den Client nur ohne Exception. Das kann’s auch nicht sein.


class Request{
...
public synchronized void  awake(Object result)
	{
		this.result = result;
		notify(); //wieder deblockieren
	}

public synchronized Object send() throws Exception {
	...		
	wait(); //warte auf Ergebnis
	...
	return this.result;
	}
}