# Threads beim Server koordinieren



## Sara3112 (17. Jun 2009)

Hallo Leute,

ich bin neu hier und ich weiß nicht genau, ob ich hier in richtige Forum schreibe. Aber ich habe ein großes Problem, woran ich schon lange sitze und ich bräuchte dringend Hilfe. Hinzu kommt das ich Programmier-Anfängerin bin. 

Also ich entwickle einen Grafik-Editor mit Chat-Funktion. Dieser soll die Möglichkeit bieten Zeichnungen zu erstellen und  mit anderen Usern zu chatten. Dabei soll aber auch die Zeichung verschickt werden können, welche dann beim Gegenüber auf das JPanel gezeichnet wird. 

Die Chat-Funktion läuft Prima. Ich hab auch schon einen Thread erstellt für die Grafikübertragung. Mein Problem ist aber, dass ich nicht weiß, wie ich beim Server sagen kann, wann er aus welchem Thread lesen soll und was er wo übertragen soll. 

Ich füge mal ein paar wichtige Code-Schnipsel hinzu, um mein Problem zu verdeutlichen.

Die Klasse ChatClient.java

```
public void actionPerformed(ActionEvent e){
		Object obj = e.getSource();
		String cmd = e.getActionCommand();
		
		try{
			if(obj == button){
                          ...
						login();
					}
				}
			}
			if(obj == text){
				if(login){
					out.write(text.getText());
					out.newLine();
					out.flush();
				}
			}
		}
		....
	}

	private void login() throws IOException{
		socket = new Socket (host, port);
		in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		
                 .....
		
		t = new Thread(this);
		t.start();
	}

	public void run(){
		try{
			while (Thread.currentThread() == t){
				final String msg = in.readLine();
				if(msg == null)
					break;
				
				doUpdate(new Runnable(){
					public void run() {
						area.append(msg + "\n"); //area ist ein JTextArea
					}
				});
			}
		}
		catch (IOException e){}
	}
```

Die Klasse Grafikuebertragung.java:


```
// hier wird das Bild auf der Zeichenfläche in den OutputStream geschrieben
    private void bildSenden() throws IOException{
		socket = new Socket(host, port);
         	cache = new ByteArrayOutputStream(64 * 1024);
		
       	if(Zeichenflaeche.buf != null){
    		System.out.println("Bild wird gesendet...");
    		ImageIO.write(Zeichenflaeche.buf, "jpeg", cache);
    		cache.flush();
    		byte[] array = cache.toByteArray();
    		final BufferedOutputStream output = new  BufferedOutputStream(socket.getOutputStream(), 64 * 1024);
    		output.write(array);
    		output.flush();
    		System.out.println("Bild wurde gesendet...");
    		
    	}	
		t = new Thread(this);
		t.start();		
	}
	
//Hier wird das empfangene Bild aus dem InputStream gelesen und in der Variablen //empfangenesBild gespeichert
	public void run(){
		try{
			while (Thread.currentThread() == t){
				
				final BufferedImage image;
				InputStream in = socket.getInputStream();
				byte[] array = new byte[64*1024];
				in.read(array);
				image = ImageIO.read(new ByteArrayInputStream(array));
				
				
				if(image == null){
		    		System.out.println("empfangenes Bild ist null");
					break;
				}
				
				doUpdate(new Runnable(){
					public void run() {
						empfangenesBild = image;
					}
				});
			}
		}
		catch (IOException e){}
	}
```

Und hier die Klasse Server:


```
public void startServer(){
		try{
			ServerSocket server = new ServerSocket(port);
			
			
			while (true){
				Socket client = server.accept();
				new ChatThread(client).start();
				new GrafikuebertragungThread(client).start();
			}
		}...

private class GrafikuebertragungThread extends Thread {
			
		private Socket gu;
		private BufferedOutputStream bildOutput;

		
		public void run(){

				bildOutput = new BufferedOutputStream(gu.getOutputStream(), 64*1024);
				
				bildManager.add(bildOutput); //bildManager ist ein Vector vpm Typ BufferedOutputStream
				
				BufferedImage image;
				InputStream in = gu.getInputStream();
				byte[] array = new byte[64*1024];
				in.read(array);
				while ((image = ImageIO.read( new ByteArrayInputStream(array))) != null){
					sendImage(image);
				}...

		}
		
		
		// schickt das Bild an alle Benutzer, die in der Variable "bildManager" gespeichert sind
		private void sendImage(BufferedImage image){
			synchronized(manager){
				for (BufferedOutputStream bildOutput : bildManager){
					ByteArrayOutputStream cache = new ByteArrayOutputStream(64 * 1024);
					try{
						ImageIO.write(image, "jpeg", cache);
						cache.flush();
						byte[] array = cache.toByteArray();
						bildOutput.write(array);
						bildOutput.flush();

					}...
				}
			}
		}
	}
	}

 //und dann hab ich halt noch eine interne Klasse ChatThread, die die Textnachrichten entsprechend weiterleitet
```

Das ist alles ein bisschen viel. Aber ich weiß nicht, was gebraucht wird, um mir helfen zu können. 
Wie gesagt, mein Problem ist, dass ich in der Klasse "Server" nicht weiß, wie ich ihm sagen soll, wann er welchen Thread benutzen soll.. Weil im Moment habe ich noch das Problem. dass er zum Beispiel, das Bild in einer Zeichenkette in der JTextArea ausgibt. 

Ich wäre euch ewig dankbar, wenn ich mir helfen könntet. Bin schon sehr verzweifelt. 

LG Sara


----------



## Sara3112 (17. Jun 2009)

Also ich hab nu rausgefunden, dass man Threads einen Namen übergeben kann. Also hab ich das in den Klassen ChatClient und Grafikuebertragung auch gemacht. Aber ich weiß immer noch nicht, wie ich in der Klasse "Server" den Namen von dem aktuellen Thread abfragen kann. Könnt ihr mir weiterhelfen?


----------



## Kaffeebohn (18. Jun 2009)

Hi Sara,

Wie es aussieht nutzt du für die gesammte Kommunikation nur eine Verbindung, das heißt alle Threads schreiben in den gleichen Stream. Ist das so gewollt?


----------



## Paddelpirat (18. Jun 2009)

Hi,

wie wäre es wenn du statt zwei unterschiedlichen Threads für Text und Grafik, nur einen Thread verwendest und dafür eine Art kleines Protokoll schreibst?

Mit Protokoll meine ich eine bestimmte Formatierung der Zeichenkette, die du über den Socket-Stream verschickst.
Zum Beispiel könnte das so aussehen, dass du am Anfang und Ende einer "Nachricht" jeweils einen Tag einfügst:

<MSG>Deine Chat-Nachricht</MSG>
<IMG>DieBytesDeinerGrafik</IMG>

Dann müsstest du in deinem Thread, der die Nachrichten vom Client erhält nur noch die Tags analysieren und könntest anhand von denen entscheiden, ob der Client eine Nachricht, oder ein Bild für die anderen Benutzer geschickt hat.

So ein "Protokoll" könnte man natürlich später noch aufbauschen mit weiteren Befehlen, z.B. wenn du eine Nachricht an eine bestimmte Person versenden möchtest etc., aber das ist ein anderes Thema :wink:


----------



## Sara3112 (18. Jun 2009)

Vielen lieben Dank für eure Antworten. An ein Protokoll habe ich anfangs auch gedacht. 
Ich benutze jetzt auch nur noch einen Thread, aber ich verwende ObjectStream, wo ich dann mit instanceof überprüfe, ob es ein image bzw ein byte[] (da ich das image in ein byte[] konvertiert habe) oder ein string ist. Das läuft eigentl auch ganz gut. Nur an einigen Stellen gibt es noch Probleme. Falls meine Anwendung noch umfangreicher werden sollte, dann werde ich wahrscheinlich auch auf das Protokoll zurückgreifen. 
Danke für eure Tipps.


----------



## tuxedo (19. Jun 2009)

Wie wär's mit RMI, SIMON oder ähnlichem?

- Alex


----------

