# 1 Socket 2 Threads problem



## Guest (1. Okt 2008)

Hi,

folgendes:

ich habe ne art telnet server den ich über den port 23 abfrage, nun möchte ich in einem thread ne art überwachung laufen haben (d.h. jede sek. werden befehle rübergeschickt und antworten eingelesen), was soweit schon läuft.
mein problem ist dass ich ja ab und zu aus dem hauptapplet auch abfragen rüberschicke und diese sollten nicht mit denen des überwachungsthreads kolidieren.

ich habe es schon mit ner art analyzer versucht der mir die antworten immer überprüft, finde die lösung aber nicht so gelungen.

habe jetzt ein wenig gegoogelt und bin auf multithreaded sockets gestoßen:
http://java.sun.com/developer/onlineTraining/Programming/BasicJava2/socket.html

kann man das so lösen ?
oder gibt es ne andere knackige lösung ?

THANX
CU


----------



## DocRandom (1. Okt 2008)

Hi!

Da wird Dir nichts anders über bleiben, als mit einer Queue auf der Serverseite zu arbeiten.

lg
DocRandom


----------



## Guest (1. Okt 2008)

Hmm auf der serverseite kann ich nix machen da es sich um ein "technisches" gerät handelt was nur auf telnet commands hört und antworten liefert.

aber ist das nicht mit den multithreaded socket so gedacht das man für jede anfrage einen neuen eigenen thread aufmacht  und den dann auch wieder beendet. damit wäre es doch getan oder ?

muß das mal ausprobieren, aber wollte mal in die runde fragen ob der ansatz schon richtig ist.

ich mach also nen thread auf schicke den befehl rüber und lese die antwort ein und währenddessen der überwachungsthread starten sollte wartet er doch bis der erste thread zu ende ist oder ?



> The multithreaded server program creates a new thread for every client request. This way each client has its own connection to the server for passing data back and forth. When running multiple threads, you have to be sure that one thread cannot interfere with the data in another thread.



CU


----------



## Guest (1. Okt 2008)

sollte das zitat oben nur für die serverseite möglich sein, gibt es ne andere lösung ?

also z.B.  den überwachungsthreadnach dem durchlauf kurz anhalten etc. ?

CU


----------



## DocRandom (1. Okt 2008)

> Hmm auf der serverseite kann ich nix machen da es sich um ein "technisches" gerät handelt was nur auf telnet commands hört und antworten liefert.


Dann mußt Du Dir einen Server basteln:
Nur dieser Server kommuniziert mit der Hardware und sonst niemand!


> aber ist das nicht mit den multithreaded socket so gedacht das man für jede anfrage einen neuen eigenen thread aufmacht  und den dann auch wieder beendet. damit wäre es doch getan oder ?


fast.
Es ist so gedacht das pro Client 1 Serverthread läuft.
Sobald der Client sich beim Server abmeldet, wird auch sein Thread beendet.(Wenn man es so programiert)


> ich mach also nen thread auf schicke den befehl rüber und lese die antwort ein und währenddessen der überwachungsthread starten sollte wartet er doch bis der erste thread zu ende ist oder ?


..nein, die beiden Threads wissen ja nichts von einander.
Wenn Du das wünscgt, dann müsstest Du dies in Deinem Kommunikationsserver einbauen!

lg
DocRandom


----------



## Guest (1. Okt 2008)

hmm kombiniere kombiniere!

also müsste es ja dann mit dem Serversocket gehen. ich mach mir nen server der dann die befehle rüberschickt und die accept() methode hindert die anderen anfragen daran gleichzeitig andere befehle rüberzuschicken.

THANX für die schnelle antwort.
CU


----------



## DocRandom (1. Okt 2008)

Du machst Dir einen Multi-Client-Server
Der Server hat *einen* Thread der die Überwachung durchführt.
Wenn der Server per *accept()* mit einem Clienten zu kominizieren beginnt, mußt Du dafür Sorge tragen, das sich die beiden Threads nicht behindern!
Das kannst Du am besten mit einer *Queue* lösen!

lg
DocRandom


----------



## Guest (1. Okt 2008)

hast du vielleicht ein beispiel für die queues ?

läuft es über die thread groups ?

CU


----------



## foobar (1. Okt 2008)

Threadsichere Collections findest du hier: http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/package-summary.html


----------



## Guest (2. Okt 2008)

komm noch mal zurück nachdem ich mir ein paar sachen angeschaut habe.

z.B.

http://www.exampledepot.com/egs/java.lang/WorkQueue.html

was ich mir nun überlegt habe wäre quasi ein thread (als server) der eben auf ein notify der queue(concurrentqueue) wartet und wenn dieser eintrifft den socket aufmacht befehl rüberschickt antwort einliest und an den sender zurück gibt.

dann macht er den socket wieder zu und wartet weiter.

kann man die antworten eigentlich wieder 

liege ich da richtig oder hat jemand ne andere idee ?


P.S. wie sende ich die antortwn an den sender zurück ? muss ich zuerst aus dem return an die queue zurücksenden und dann an die methode oder geht´s auch einfacher?
kennt jemand vielleicht ein gutes beispiel für sowas ähnliches ?

THANX 
CU


----------



## DocRandom (3. Okt 2008)

Hi!

Um Deinem herumraten ein Ende zu bereiten, werde ich Dir in etwa zeigen wie Du es machen kannst.
*Der Code ist teilweise nicht getestet, sonern dient zum Verständnis!*

Wir brauchen eine *Queue*, die Threadsicher ist, hier mein Vorschlag:

```
package gast;

import java.util.LinkedList;
import java.util.Queue;

public class FifoQueue<T> {

   private Queue<T> queue;
   
   public FifoQueue() {
      queue = new LinkedList<T>();
   }
   public synchronized void addElement( T o ) {
      queue.add( o );
      notify();
   }
   public synchronized T getElement() {
      T o = null;
      if(!queue.isEmpty())
         o = queue.poll();
      
      notify();
      return o;
   }
   public int getCount() {

      return queue.size();
   }
}
```
 Als nächstes benötigen wir 2 Warteschlangen für die Komminikation.
Beide leiten sich von der *FifoQueue* ab und werden als Singleton eingerichtet:

```
package gast;

public class CommandQueue extends FifoQueue<Message>{

	private static CommandQueue INSTANCE = null;
	
	private CommandQueue() {
		super();
	}
	
	public static synchronized CommandQueue getInstance() {
		if(INSTANCE == null)
			INSTANCE = new CommandQueue();
		
		return INSTANCE;
	}
}
```


```
package gast;

public class MessagesQueue extends FifoQueue<String>{

	private static MessagesQueue INSTANCE = null;
	
	private MessagesQueue() {
		super();
	}
	
	public static synchronized MessagesQueue getInstance() {
		if(INSTANCE == null) 
			INSTANCE = new MessagesQueue();
		
		return INSTANCE;
	}
}
```
Weiters benötigen wir für die CommandQueue ein Message-Object:

```
package gast;

public class Message {

	private Sender who;
	private String what;
	
	public Message(Sender who, String what) {
		this.who = who;
		this.what = what;
	}
	
	public Sender getWho() {
		return this.who;
	}
	
	public String getWhat() {
		return this.what;
	}
	
	public void setWhat(String msg) {
		this.what = msg;
	}
}
```
..und die Enum-Klasse zur Kennzeichnung wer der Absender ist:

```
package gast;

public enum Sender {
	SERVER, CLIENT, SYSTEM
}
```
Dies wäre mal unser Grundgerüst.
Die überlegung ist dahingehend, das alle 1000ms (1 sekunde) eine Kontrollanfrage an Dein Tool zu senden ist.
Für diese Aufgabe verwenden wir einen ServiceThread, der jede Sekunde einen Befehl in die CommandQueue stellt:


```
package gast;

public class ServiceThread extends Thread{

	private CommandQueue cq;
	private long waittime = 1000;
	
	public ServiceThread() {
		cq = CommandQueue.getInstance();
	}
	@Override
	public void run() {
		
		while(true) {
			// auf Abbruch testen
			if(this.interrupted())
				break;
			// neues Message-Object erzeugen
			Message msg = new Message(Sender.SERVER, "Dein Ueberwachungsbefehl");
			// in die CommandQueue schieben
			cq.addElement(msg);
			// schlafen gehen
			try {
				sleep(waittime);
			} catch (InterruptedException e) {
				e.printStackTrace();
				interrupt();
			}
		}
		
	}
}
```
Da auch Clients mit dem Server kommunizieren sollen, brauchen wir einen Thread für den Clienten:

```
package gast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class ClientThread extends Thread{

	private CommandQueue cq;
	private MessagesQueue mq;
	private Socket cs = null;
	private BufferedReader br = null;
	private BufferedWriter bw = null;
	
	public ClientThread(Socket cs) {
		// CommandQueue holen
		cq = CommandQueue.getInstance();
		// MessagesQueue holen
		mq = MessagesQueue.getInstance();
		// Verbindung setzen
		this.cs = cs;
		try {
			br = new BufferedReader(new InputStreamReader(cs.getInputStream()));
			bw = new BufferedWriter(new OutputStreamWriter(cs.getOutputStream()));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void run() {
		
		String line;
		try {
			// Clientcommando senden
			while((line = br.readLine()) != null ) {
				Message msg = new Message(Sender.CLIENT, line);
				cq.addElement(msg);
			}
			// auf Antwort warten
			while (true) {
				while (mq.getCount() == 0) {
					sleep(100);
				}
				String msg = mq.getElement();
				// Ende der Nachricht?
				if (msg.equals("-ENDE-")) 
					break;
				bw.write(msg);
				bw.flush();
			}
		}catch (IOException io) {
			io.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
			interrupt();
		}
		try {
			if (br != null ) {
				br.close();
			}
			if (bw != null) {
				bw.close();
			}
			if (cs != null) {
				cs.close();
			}
		}catch (IOException e) {
			
		}
	}
}
```
..und zu guter letzt einen Thread, der alles verarbeitet, ich habe Ihn WorkerThread getauft:

```
package gast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class WorkerThread extends Thread {

	private CommandQueue cq;
	private MessagesQueue mq;
	private long waittime = 100;
	private BufferedReader br = null;
	private BufferedWriter bw = null;

	public WorkerThread(Socket s) {
		// CommandQueue holen
		cq = CommandQueue.getInstance();
		// MessageQueue holen
		mq = MessagesQueue.getInstance();
		// Socket zuweisen;
		try {
			br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void run() {

		try {
			while (true) {
				// auf Abbruch testen
				if (this.interrupted())
					break;
				// Commando-Objekt holen
				Message msg = cq.getElement();
				// Commando senden
				bw.write(msg.getWhat());
				bw.flush();
				// auf antwort warten
				String response;
				while ((response = br.readLine()) != null) {
					// auf Client testen
					if (msg.getWho() == Sender.CLIENT) {
						// ja, response in die MessageQueue schieben
						mq.addElement(response);
					} else {
						// was auch immer zu machen ist
						// am besten auch in eine Queu zur weiterverarbeitung
					}

				}
				// Ende der Uebertragung
				// evtl. Ende fuer Client Kennzeichnen
				if (msg.getWho() == Sender.CLIENT)
					mq.addElement("-ENDE-");

				// Thread schlafen legen, wenn nichts in der CommandQueue ist
				while (cq.getCount() == 0) {
					sleep(waittime);
				}
			}

		} catch (IOException e) {
			e.printStackTrace();
			this.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
			interrupt();
		} finally {
			try {
				if (br != null) {
					br.close();
				}
				if (bw != null) {
					bw.close();
				}
			} catch (IOException io) {
				io.printStackTrace();
			}
		}

	}

}
```
Service-Thread & ClientThread füllen die CommandQueue.
Der ClientThread wartet auch noch auf eine Rückmeldung.
Der WorkerThread übernimmt die Kommunikation zwichen Deinem Tool und der Queue, außerdem gibt er evtl.
Messages in die MessagesQueue zurück.
Wie Du den Server und die div. Verbindungen aufbaust, wirst Du hoffentlich wissen!

lg
DocRandom


----------



## Guest (5. Okt 2008)

Super! vielen Dank !

werde gleich morgen alles implementieren.
CU


----------



## foobar (6. Okt 2008)

> Wir brauchen eine Queue, die Threadsicher ist, hier mein Vorschlag:


Das gibts doch schon: 
http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html
http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ArrayBlockingQueue.html


----------



## DocRandom (6. Okt 2008)

..jo, weiß ich das es das schon gibt!
Habe aber dennoch alten Code von mir verwendet.

Oder darf man/frau das nicht mehr?

lg
DocRandom


----------

