Socket-Thread: Designfrage

Status
Nicht offen für weitere Antworten.
T

tuxedo

Gast
Hallo zusammen,

hab mal eine kleine Designfrage:

Ich hab eine Klasse (die als Thread realisiert ist) die eingehende Anfragen vom Socket liest und "beantwortet". Das geschieht in der "Endlosschleife" des Threads. Parallel dazu habe ich 2 Methoden die selbst Anfragen an den "Gegenüber" senden und eine Antwort erwarten. Das ganze passt jetzt nicht so einfach zusammen weil ich ja a) in der Endlosschleife vom Socket lese und b) in einer der beiden Methoden sende und danach ebenfalls lese.

Ich versuch mal die aktuelle Situation zu skizzieren:

Code:
class SocketThread extends Thread {

public void run() {
   while (!interrupted()){
      packetHandler.process(objectInputStream.readObject());
   }
}

public Object sendMethodA(Object someDataA){
   objectOutputStream.writeObject(someData);
   return objectInputStream.readObject();
}

public Object sendMethodB(Object someDataB1, Object someDataB2){
   objectOutputStream.writeObject(someDataB1);
   objectOutputStream.writeObject(someDataB2);
   return objectInputStream.readObject();
}


Man sieht schnell dass da was in die Hose geht. Ich kann ja nicht an zwei Stellen vom Stream lesen ohne dass ich Konsistentprobleme bekomme. Das ganze muss nun irgendwie asynchron laufen:

Empfangen geschieht ausschließlich an der einen Stelle (Schleife), senden an einer anderen (weitere Methoden).

Mein erster Ansatz wäre jetzt folgender (am Beispiel "sendMethodA()"):

Code:
public Object sendMethodA(Object someDataA){
   int anfrageId = this.generateAnfrageId();

   objectOutputStream.writeObject(someData);

   while (!receivedAnswers.containsKey(anfrageId){
      Thread.sleep(1);
   }

   return receivedAnswers.get(anfrageId);
}

Ich lass mich eine eindeutige ID für meine Anfragen generieren, sende meine Anfrage und warte dann, bis mir der PacketHandler (der, der ion der endlosschleife in der run() Methode läuft) die passende Antwort dazu in einer HashMap (oder sonstwas) zur Verfügung stellen kann. Dann nehme ich die Antwort und liefere sie als return-Wert. Das ganze ließe sich natürlich noch mit einem TimeOut belegen.

Prinzipiell müsste das funktionieren. Doch mich stört daran, dass ich ein Sleep() einbauen muss. Zudem weiß ich nicht wie effizient es ist eine HashMap auf diesem Wege nach dem "vorhandensein" der passenden Antwort zu fragen.
Am geschicktesten wäre es, wenn sich die Methode nach dem senden schlafen legen würde, und erst dann - getriggert vom PacketHandler - weiter macht wenn die Antwort da ist.

Hat da jemand nen Tipp für mich? Sollte halt möglichst effizient sein.

- Alex
 

schalentier

Gesperrter Benutzer
Also ueblicherweise wuerde man einen Thread nehmen (oder einen Mainloop und dort "pollen") und da das Empfangen realisieren. Dazu das Empfangene in einzelne Meldungsobjekte (Packets) zerlegen und diese in eine Warteschlange packen.

An einer anderen Stelle im Programm (zweiter Thread oder ebenfalls im Mainloop pollen) wird diese Warteschlange abgearbeitet, also immer das letzte Packet nehmen und verarbeiten.

Deine Methoden (sendMethodA und B) musst du dann auftrennen in eine zum Senden und eine zum Verarbeiten der Packets. D.h. das ganze wird damit asynchron. Die sendMethods senden nur und anschliessend laeuft dein Programm weiter. Reagiert wird erst, wenn das Antwortpacket eingetroffen ist.

Wenn du mit Threads arbeitest muss die Queue natuerlich synchronisiert werden (so dass nicht gleichzeitig in die Queue geschrieben und aus ihr gelesen wird).
 
T

tuxedo

Gast
schalentier hat gesagt.:
Also ueblicherweise wuerde man einen Thread nehmen (oder einen Mainloop und dort "pollen") und da das Empfangen realisieren. Dazu das Empfangene in einzelne Meldungsobjekte (Packets) zerlegen und diese in eine Warteschlange packen.

Das hört sich nach dem was ich in meinem ersten Ansatz versucht habe zu formulieren: Einen Thread der in einer Schleife nix weiter macht wie Pakete empfangen und in einer Liste/Warteschlange zu packen.

An einer anderen Stelle im Programm (zweiter Thread oder ebenfalls im Mainloop pollen) wird diese Warteschlange abgearbeitet, also immer das letzte Packet nehmen und verarbeiten.

Deine Methoden (sendMethodA und B) musst du dann auftrennen in eine zum Senden und eine zum Verarbeiten der Packets. D.h. das ganze wird damit asynchron. Die sendMethods senden nur und anschliessend laeuft dein Programm weiter. Reagiert wird erst, wenn das Antwortpacket eingetroffen ist.

Naja, das ist ein kleines Problem. Ich will da eigentlich mit meinen Sende-Methoden (sind wirklich nur 2) das Frage-Antwort-Prinzip verfolgen. Vergleichbar mit der Anfrage eins Browsers an einen Webserver: Anfrage geht raus, Webserver antwortet, Seite wird angezeigt.
D.h. ich brauche am Ende der Methode einen passenden Return-Wert.

[/quote]
Wenn du mit Threads arbeitest muss die Queue natuerlich synchronisiert werden (so dass nicht gleichzeitig in die Queue geschrieben und aus ihr gelesen wird).[/quote]

Das ist klar.


Wenn ich die Sende-Methoden, die UNBEDINGT eine Antwort für ihren Returnwert brauchen in einen eigenen Thread auslagere:

Kann ich dann irgendwie den Thread nach dem Senden anhalten und von außen wieder wecken?
Weil dann könnte ich folgendes tun:

Der Sende-Thread registriert sich beim PacketHandler und teil dem mit: "Wenn du ein Paket empfängst das die AnfrageID XYZ hat: Bitte mich wieder aufwecken". Eben ähnlich einem Eventlistener. Nur dass ich die Ausführung der Methode durch einen Thread "schlafen lege" bis das Event eintritt.

Thread#suspend() und Thread#resume() sind ja leider deprecated .. Gibts da ein brauchbares "workaround"?

Wenn das geht, dann hab ich ja erreicht was ich wollte...Ich könnte das auch mit einem Sleep und einem polling der Warteschlange der empfangenen Pakete machen. Aber das wäre wohl weniger schnell/performant, oder? Mir gehts hier um jede Millisekunde.

- Alex
 

schalentier

Gesperrter Benutzer
Pfff... also 1 Thread pro Methodenaufruf, der einfach nur auf die Antwort wartet, wird wohl ziemlich langsam werden. Ich hab jetzt keine richtigen Thread-Benchmarks, auf die ich verweisen koennte, aber imo basieren die Java-Threads auf Betriebssystem-Prozessen. Und die brauchen ihre Zeit zum initialisieren usw.

Kann dabei evtl. RMI irgendwie helfen? Ich bin da nich ganz so firm... aber sind RMI's nicht auch synchronisiert? Google sollte helfen... (bin grad aufm Sprung ^^).

Das ganze schreit aber nach Erlang. Erlang kann genau das, was du willst und zwar sehr schnell und verteilt auf mehrere Cores/Prozessoren/Maschinen. Wenn du also mal was neues lernen willst... nimm Erlang dafuer ;-)
 
T

tuxedo

Gast
Ich glaube das hier ist genau das was ich brauche:

Code:
public class MyThreadTest {
	
	
	public class MyThread extends Thread {
		boolean sleepMode = false;

		// This method is called when the thread runs
		public void run() {

				// Do work
				System.out.println("Arbeit A");
				
				goToSleep();

				// Do work
				System.out.println("Arbeit B");

		}
		
		public void goToSleep(){
			System.out.println("goToSleep()");
			sleepMode = true;
			synchronized (this) {
				while (sleepMode) {
					try {
						System.out.println("wait");
						wait();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
		
		
	}

	public static void main(String[] args) throws InterruptedException {

		// Create and start the thread
		MyThread thread = new MyThreadTest().new MyThread();
		
		// Thread starten und Arbeit A beginnen
		thread.start();
		
		// ein bisschen warten bis Arbeit A erledigt ist
		Thread.sleep(5000);


		// Aufwecken und Arbeit B erledigen lassen
		System.out.println("wecke auf");	
		synchronized (thread) {
			thread.sleepMode=false;
			thread.notify();	
		}
		

			
			

	}

	

}

Damit kann ich prima den Thread schlafen legen und auch wieder aufwecken. Warum ich beim Aufwecken unbedingt das "synchronized { ... }" brauche weiß ich noch nicht... Aber funktionieren tuts schonmal so.

- Alex
 

Niki

Top Contributor
Meiner Meinung nach musst du vor dem Senden ein Object erstellen (dies ist dein syncMonitor). dieses Object stellst du mit einer generierten ID in eine HashMap. Dann rufst du das Senden auf (im synchronized-block des Objects) und legst dich anschließend in den wait pool.
Der Empfänger-Thread bekommt dann die ID zurück, schaut nach ob es ein Objekt in der HashMap dafür gibt und holt sich dieses. Das Ergebnis des Empfängers wird wieder mit der ID als Schlüssel in eine Map gespeichert. Anschließend ruft der Empfänger auf dem Object die notify Methode auf und löscht das Objekt aus der Map raus:

Code:
public static final HashMap<Integer, Object> ID_MONITOR_MAP = new HashMap<Integer, Object>();

public static final HashMap<Integer, Object> RESULTS = new HashMap<Integer, Object>();

public Object send(Object o) throws Exception{
  Integer id = generiereID();
  Object monitor = new Object();
  ID_MONITOR_MAP.put(id, monitor);
  synchronized(monitor){
    objectOutputStream.writeObject(o);
    monitor.wait();
  }
  Object result = RESULTS.get(id);
  RESULTS.remove(id);
  return result;
}

//hier der Thread...
public void run(){
  while(true){
    Object o = objectInputStream.readObject();
   //irgendwie muss ja der Schlüssel zurück:
    Integer key = ...;
    RESULTS.put(key, o);
    Object monitor = ID_MONITOR_MAP.get(key);
    synchronized(monitor){
      monitor.notify();
    }
    ID_MONITOR_MAP.remove(key);
  }
}

Könnte klappen, oder?
 
T

tuxedo

Gast
Nachtrag:

Nein, nicht nur ein Thread ...

Ich hab ein Thread der pollt den Socket nach neuen Nachrichten. Und ich hab je einen Thread für das jeweilige Nachricht senden. Nur wartet der Methodenaufruf der die Nachricht absendet, bis der Empfang-Thread SEINE Nachricht empfangen hat. Und erst dann beendet sich die Sende-Methode im SendeThread und liefert das Ergebis der Anfrage zurück.

RMI? Nein, das ist nicht wirklich eine Lösung. Grund:

Ich versuche gerade einen RMI-Ersatz zu schreiben ;-) Einer der nur eine einzige Socketverbindung benutzt.

- Alex
 

Niki

Top Contributor
Bei meiner Lösung kannst du soviele Thread wie du willst verwenden, die senden Methode wartet solange bis sie vom Empfänger benachrichtigt wird.
 

ms

Top Contributor
@Alex
Den Ansatz mit wait() und notify() wollte ich auch schon vorschlagen.

ms
 
T

tuxedo

Gast
@Niki

Jupp, sowas bastle ich gerade. Nur ist dein Ansatz noch n bisschen "einfacher". Hab da gerade irgendwie zu komplex angefangen.

Danke soweit für die Ratschläge ...

- Alex
 
T

tuxedo

Gast
Danke Leute,

die Sache hat bestens geklappt. Hab nur noch was an einer zweiten Stelle entkoppeln müssen.

Mein RMI-Ersatz läuft schon prima. "Normales" Methodenaufrufen auf dem Server, sowie Callbacks funzen astrein.

ENDLICH was RMI-artiges was nur eine Socketverbindung benutzt *chacka*. Muss noch ein wenig feinarbeit machen. Dann schau ich mal unter welche Lizenz ich das ganze Stelle.

- Alex
 
T

tuxedo

Gast
Hallo nochmal ...

Hab ein kleines Problemchen. Habs so gelöst wie Niki vorgeschlagen hat.

Doch dauert das aufwecken, wenn ich client und server auf getrennten maschinen laufen lasse, um 300..400ms .....

Lasse ich Client und Server lokal lauf, so hab ich meistens 0ms aufweckzeit (also die zeit von schlafebn gehen, bis wieder aufwachen).

Der Client schickt ja eine Frage zum Server. Dann schläft er, bis er die Antwort empfangen hat und aufgeweckt wird. Der Server antwortet jedoch sowas von unmittelbar, dass es nicht am Server liegen kann. Die Nachricht ist also schon wieder da, nur dauert das Wecken zu lange ...

Any ideas?

- Alex
 

Niki

Top Contributor
Was genau dauert so lange? Nur das aufwecken also MONITOR.notify() oder das deserialisieren des Objektes?
 

lhein

Top Contributor
Also wenn ich den Thread hier so lese, dann drängt sich mir unmittelbar die Frage auf, warum Du nicht eine Lib wie xSocket verwendest, die Dir schon einen Non-Blocking NIO Server an die Hand gibt und einfach dort Deinen Handler integrierst. Damit hättest Du den Server mal recht einfach realisiert und kannst sicher sein, daß der optimal funktioniert.
Bliebe dann nur noch der Client.

Oder hab ich hier was übersehen?

lr
 
T

tuxedo

Gast
@LR

Naja, ich habs so modular aufgebaut, dass ich recht einfach auf eine andere socket-realisierung aufbauen kann.

@Niki

Hab den schuldigen.... Nicht das wecken dauert so lange, sondern das Netzwerk war "lahm". Bzw. nicht das Netzwerk selbst.

Ich hab gecheckt wie lange der Server rbaucht um die Anfrage entgegen zu nehmen, zu bearbeiten und die Antwort zu senden. Belief sich auf fast 0ms...

Nach ein wenig rumprobieren bin ich drauf gekommen: Die Standard TCP-Einstellungen ist schuld.

Wenn man den Nagle-Aglorithmus abschaltet und das ganze noch etwas feintuned, dann geht's rucki-zucki. Das Delay von 300...400ms ist nun komplett weg.

Hab einfach nach dem herstellen der Socketverbindung beim Client als auch beim Server folgendes eingebaut:

Code:
socket.setTcpNoDelay(true); // nagle-algo abschalten, siehe [url]http://de.wikipedia.org/wiki/Nagle-Algorithmus[/url]
			socket.setTrafficClass(0x10); // low delay
			socket.setPerformancePreferences(0, 2, 1); // prio: geringe latenz > bandbreite > verbindungzeit

Bin mir nur nicht ganz sicher ob das "sicher" ist oder ob ich mir damit nicht noch Probleme einfange. Bei meiner Diplomarbeit (da ging um Audiokonferenz mit Java) hab ich das genau so gemacht. Aber da isses wurscht ob ein einzelnes Paket "abraucht" oder nicht.

- Alex

p.s. flush() hatte ich schon überall drin ... Daran lags also nicht.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
platofan23 Socket Hilfe mit Socket Thread und ArrayList Netzwerkprogrammierung 6
D Socket Dynamische Socket-Thread Erzeugung Netzwerkprogrammierung 2
Z Socket Socket-Thread falsch? Netzwerkprogrammierung 5
S Thread, Daten vom Socket lesen Netzwerkprogrammierung 2
W Socket Server -> lesen von / schreiben zu php-script Netzwerkprogrammierung 6
B Versuch mit Socket etwas zu lesen und zu schreiben Netzwerkprogrammierung 15
G Socket Socket Kommunikation Netzwerkprogrammierung 1
L Server-Socket liest Input-Stream nicht Netzwerkprogrammierung 5
H Socket Kann ein Socket server 2 dimensionale Arrays empfangen und versenden? Netzwerkprogrammierung 3
D Socket-Verbindungen übers Internet Netzwerkprogrammierung 4
Z Kann nicht Daten vom Server lesen Socket Netzwerkprogrammierung 10
N Java socket Programmierung Filme verschicken Netzwerkprogrammierung 20
A TCP multiClientServer mit socket mittels ObjectOutputStream Netzwerkprogrammierung 12
A Socket-Anwendung (BufferedWriter/Reader liest nicht aktuellen Wert) Netzwerkprogrammierung 6
platofan23 Socket Java Socket mit DynDns nicht erreichbar Netzwerkprogrammierung 6
S Socket Bilder über Socket Senden Netzwerkprogrammierung 0
M Socket Socket lehnt Verbindung ab Netzwerkprogrammierung 3
x46 Connection reset by peer: socket write error Netzwerkprogrammierung 6
x46 Socket Files per Socket verschicken Netzwerkprogrammierung 1
platofan23 Probleme mit Socket bei Android Studio? Netzwerkprogrammierung 22
R Socket FATAL EXCEPTION MAIN bei Socket based client/server app Netzwerkprogrammierung 2
D new ObjectInputStream(socket.getInputStream()); Netzwerkprogrammierung 15
E Socket Frage Netzwerkprogrammierung 6
D ServerSocket - Socket Verbindungsart Netzwerkprogrammierung 3
T Frage bzgl. Socket-API Netzwerkprogrammierung 1
F TCP Socket auf Verbindungsabbruch prüfen Netzwerkprogrammierung 15
F Socket Verbindung mit Verschlüsselung und Authentifierzung Netzwerkprogrammierung 1
I Socket ObjectOutputStream-Socket: Objekt wird falsch übertragen Netzwerkprogrammierung 2
T Socket Socket connections schließen? Netzwerkprogrammierung 2
D Socket Socket OutputStream leeren? Netzwerkprogrammierung 3
T Socket Java Programm hängt sich auf bei dem versuch von einem Socket scanner Daten zu erhalten. Netzwerkprogrammierung 1
F Socket Socket in anderen Methoden Netzwerkprogrammierung 1
D Socket Run Args Client/Server Socket Netzwerkprogrammierung 1
M Problem bei Socket (MultiplayerSpiel) Netzwerkprogrammierung 4
I Socket Netzwerkprogrammierung 1
F Wiederverbinden nach socket Abbruch Netzwerkprogrammierung 1
J 1 Socket - 2 Serversocket Netzwerkprogrammierung 4
T Socket sendet erst nach socket.close() Netzwerkprogrammierung 2
F Socket Verbindungsaufbau abbrechen Netzwerkprogrammierung 3
P Socket Socket-Verbindung Input sehr langsam Netzwerkprogrammierung 1
I Socket Kommunikation C / Java Netzwerkprogrammierung 2
Joew0815 socket event handler Netzwerkprogrammierung 2
F Einfache Socket Verbindung Netzwerkprogrammierung 2
A Socket Socket Receive-/SendBuffersize Netzwerkprogrammierung 0
D Socket server auf Smartphone Netzwerkprogrammierung 9
H Socket Client/Server Socket Programmieren Netzwerkprogrammierung 1
A Socket Socket Server netcat Netzwerkprogrammierung 1
Shams Anfängerfrage zu Server-Socket-Kommunikation Netzwerkprogrammierung 2
M Socket String Arrays über Socket an Server schicken Netzwerkprogrammierung 2
D Socket Error: java.lang.NullPointerException Netzwerkprogrammierung 1
D TCP Socket funktioniert nicht richtig Netzwerkprogrammierung 3
X Problem mit vielen Bytes über Socket Netzwerkprogrammierung 23
B SSL Socket Netzwerkprogrammierung 2
A Socket Socket-Problem - Object wird nicht übertragen Netzwerkprogrammierung 3
M Client sendet nur, wenn das Socket geschlossen wird Netzwerkprogrammierung 53
R Dauerhaft offene Socket-Verbindung? Netzwerkprogrammierung 3
S Socket (client) verbindet nicht Netzwerkprogrammierung 6
G Socket Socket verbindung für Chat System Netzwerkprogrammierung 3
P Warum kann ich kein Socket aufbauen? Netzwerkprogrammierung 12
S Socket SSL Socket und Sun/Oracle Java Netzwerkprogrammierung 5
S Socket Socket Verbindung wiederherstellen Netzwerkprogrammierung 16
precoc Server Socket Start / Stop Netzwerkprogrammierung 5
N SOCKET mehrere Requests, keep Alive serverspezifisch? Netzwerkprogrammierung 3
S ImageIcon über Socket schicken (Serialisierung) Netzwerkprogrammierung 6
C Socket Systemsperren mit Socket Netzwerkprogrammierung 4
H Socket Objekte über Socket? Allgemeine Verständnisprobleme in Sachen Socket Netzwerkprogrammierung 3
D Socket Multithread-Socket | Kurz vor dem Ziel Netzwerkprogrammierung 7
C Datei über Socket schreiben und Ereignis lesen Netzwerkprogrammierung 9
D Socket Socket absichtlich so schließen, dass Gegenseite java.net.SocketException: Connection reset wirft Netzwerkprogrammierung 4
J Socket Dateien über Socket auf Server speichern Netzwerkprogrammierung 3
S Socket-Frage zu einem LAN-Spiel. Netzwerkprogrammierung 3
A UDP verlorene Pakete/ socket.receive zu langsam Netzwerkprogrammierung 27
CookieSoft Socket Packet per Socket Netzwerkprogrammierung 8
CookieSoft Fehler bei Socket Netzwerkprogrammierung 4
D Socket Datei nur stückweise über Socket verschicken Netzwerkprogrammierung 6
T Per Socket auf POP3 zugreifen? Netzwerkprogrammierung 7
G Bild über Socket schicken - Client/Server Netzwerkprogrammierung 10
Helgon Socket Socket IP Frage + Tutorial/Bücher Netzwerkprogrammierung 5
S Socket Verschiedene Exceptions beim Übertragen von Bildern über Socket Netzwerkprogrammierung 20
T Socket String zu Socket Netzwerkprogrammierung 26
M Datenübertragung per Socket nur alle 200ms Netzwerkprogrammierung 4
C Socket Socket: Connection timed out Netzwerkprogrammierung 3
T Socket blockierter Socket Netzwerkprogrammierung 4
C Socket Probleme beim Lesen und Schreiben aus/in einen Socket Netzwerkprogrammierung 2
T Alternative Socket mit Verbindungsabbruch Erkennung Netzwerkprogrammierung 2
M Socket, Ende Dateitransfer Netzwerkprogrammierung 4
X Über eine Socket-Verbindung Arrays übergeben Netzwerkprogrammierung 5
D RMI oder Socket Netzwerkprogrammierung 4
H Socket Socket listening Netzwerkprogrammierung 11
D Client Socket mit Eventlistener? Netzwerkprogrammierung 5
P Socket Verbindung über das Internet Netzwerkprogrammierung 2
A Socket Netzwerkprogrammierung 18
N Socket geht auf Windows, aber auf Mac nicht ? Netzwerkprogrammierung 3
ruffio1978 Telnet über ein socket ansprechen Netzwerkprogrammierung 8
G Exception: Connection reset by peer: socket write error Netzwerkprogrammierung 2
M SSl Socket Server und openssl key Netzwerkprogrammierung 3
J Socket Socket Programmierung. Wie anfangen? Netzwerkprogrammierung 4
DEvent Keine IOException beim schreiben Socket Netzwerkprogrammierung 3
A Socket Server: Message an verschiedene Clients senden Netzwerkprogrammierung 4
F Socket Verbindungen über mehrere Server Netzwerkprogrammierung 4

Ähnliche Java Themen


Oben