# Zähler zählt nicht hoch



## Miramizu (24. Nov 2010)

Hallo,

Ich habe ein ziemliches Problem und komm einfach nicht auf die Lösung.

Die Aufgabe ist, ein Spiel zu programmieren, ich habe Schere, Stein, Papier gewählt. Der Server startet und zwei Clients melden sich an. Dann geben sie eine Zahl ein, die entweder für Schere, oder papier, oder eben Stein steht und dann kommt die ausgabe wer gewonnen hat.

Das Problem ist, dass dieser Spieldurchgang mindestens zweimal gemacht werden muss, da man erst gewinnt, wenn man mindestens 2 mal gewonnen hat.

Ein Durchgang funktioniert einwandfrei, doch dann passiert einfach nichts mehr, und das Terminal bleibt leer...

Ich starre nun schon seit Stunden auf den Code vom Serverthread und komme einfach nicht auf die Lösung... Vielleicht wird der Counter nicht hochgezählt, ich verstehe aber nicht, wieso...

Ich brauche nun DRINGENST Hilfe, da ich das Projekt bald abgeben muss...



Hier sind die Codes:

Serverthread:

```
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class ServerThread extends Thread {
	
	private Socket client1;
	private Socket client2;
	int indexclient1 = 0;
	int indexclient2 = 0;
	
	public ServerThread(Socket client1, Socket client2)
	{
		this.client1 = client1;
		this.client2 = client2;
	}
	
		public void run()
		{
			try{
			DataInputStream input1 = new DataInputStream(client1.getInputStream());
			DataInputStream input2 = new DataInputStream(client2.getInputStream());
			DataOutputStream output1 = new DataOutputStream(client1.getOutputStream());
			DataOutputStream output2 = new DataOutputStream(client2.getOutputStream());
			
			do
			{
				int a = input1.readInt();
				System.out.println("Checkpoint 1");
				int b = input2.readInt();
				System.out.println("Checkpoint 2");
			
				if(a == 1 && b == 1)
				{
					output1.writeChars("Das Match ist unentschieden !\n");
					output2.writeChars("Das Match ist unentschieden !\n");
					output1.flush();
					output2.flush();
				}
				else if(a == 1 && b == 2)
				{
					output1.writeChars("Sie haben das Match verloren !\n");
					output2.writeChars("Sie haben das Match gewonnen !\n");
					output1.flush();
					output2.flush();
					indexclient2++; 
				}
				else if(a == 1 && b == 3)
				{
					output2.writeChars("Sie haben das Match verloren !\n");
					output1.writeChars("Sie haben das Match gewonnen !\n");
					output1.flush();
					output2.flush();
					indexclient1++;
				}
				else if(a == 2 && b == 1)
				{
					output2.writeChars("Sie haben das Match verloren !\n");
					output1.writeChars("Sie haben das Match gewonnen !\n");
					output1.flush();
					output2.flush();
					indexclient1++;
				}
				else if(a == 2 && b == 2)
				{
					output1.writeChars("Das Match ist unentschieden !\n");
					output2.writeChars("Das Match ist unentschieden !\n");
					output1.flush();
					output2.flush();
				}
				else if(a == 2 && b == 3)
				{
					output1.writeChars("Sie haben das Match verloren !\n");
					output2.writeChars("Sie haben das Match gewonnen !\n");
					output1.flush();
					output2.flush();
					indexclient2++; 
				}
				else if(a == 3 && b == 3)
				{
					output1.writeChars("Das Match ist unentschieden !\n");
					output2.writeChars("Das Match ist unentschieden !\n");
					output1.flush();
					output2.flush();
				}
				else if(a == 3 && b == 2)
				{
					output2.writeChars("Sie haben das Match verloren !\n");
					output1.writeChars("Sie haben das Match gewonnen !\n");
					output1.flush();
					output2.flush();
					indexclient1++;
				}
				else if(a == 3 && b == 1)
				{
					output1.writeChars("Sie haben das Match verloren !\n");
					output2.writeChars("Sie haben das Match gewonnen !\n");
					output1.flush();
					output2.flush();
					indexclient2++; 
				}
				
				if(indexclient1 <= 2 && indexclient2 <= 2 )
				{
					output1.writeBoolean(false);
					output2.writeBoolean(false);
					System.out.println("False");
					output1.flush();
					output2.flush();
				}
				else
				{
					output1.writeBoolean(true);
					output2.writeBoolean(true);
					System.out.println("True");
					output1.flush();
					output2.flush();
				}
				
				System.out.println("Checkpoint 3");
			}while(indexclient1 <= 2 && indexclient2 <= 2);
			System.out.println("Checkpoint 4");
			
				if(indexclient1 == 2)
				{
					output1.writeChars("Sie haben das Spiel gewonnen !\n");
					output2.writeChars("Sie haben das Spiel verloren !\n");
				}
				else if(indexclient2 == 2)
				{
					output2.writeChars("Sie haben das Spiel gewonnen !\n");
					output1.writeChars("Sie haben das Spiel verloren !\n");
				}
			output1.flush();
			output2.flush();
			System.out.println("Checkpoint 5");
			input1.close();
			input2.close();
			output1.close();
			output2.close();
			client1.close();
			client2.close();
			}
		catch(IOException e){
			System.out.print(e);
			e.printStackTrace();
			}
		}
}
```


falls noch wichtig hier noch die Client und Server Codes:
Client:


```
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.util.Scanner;

public class Client {
	
	private boolean finish = false;
	
	Client(String IP, int port) throws IOException {
				
		Socket server = new Socket(IP, port);
		DataInputStream input = new DataInputStream(server.getInputStream());
		BufferedReader input1 = new BufferedReader(new InputStreamReader(server.getInputStream())); 
		DataOutputStream output = new DataOutputStream(server.getOutputStream());
		Scanner scanner = new Scanner(System.in);
		while(!finish)
		{
			System.out.println("Bitte waehlen Sie Ihre Waffe:");
			System.out.println("[1] Schere"+"\n"+"[2] Stein"+"\n"+"[3] Papier"+"\n");
			int a = scanner.nextInt();
			output.writeInt(a);
			output.flush();
			System.out.println("Checkpoint 0 \n");
			if(a == 1)
			{
				System.out.println("Sie haben --Schere-- gewaehlt");
			}
			else if(a == 2)
			{
				System.out.println("Sie haben --Stein-- gewaehlt");
			}
			else
			{
				System.out.println("Sie haben --Papier-- gewaehlt");
			}
			String str = input1.readLine();
			str = str.replace(str.charAt(0), " ".toCharArray()[0]);
			System.out.println(str);
			System.out.println("Checkpoint 1");
			finish = input.readBoolean();
		}
		System.out.println("\n" + "\n" + input1.readLine());
		server.close();
		input.close();
		output.close();
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {	
			new Client (args[0], new Integer(args[1]));
		} catch (IOException e){
			System.out.print(e);
		}
					

	}
}
```

Server:

```
import java.net.*;
import java.io.*;

public class Server {
	
	static ServerSocket server; 
	
	Server() throws IOException {
		while (true) {
			System.out.println("Wartet auf Spieler 1");
			Socket client1 = server.accept();
			System.out.println("Wartet auf Spieler 2");
			Socket client2 = server.accept();
			ServerThread serverTh = new ServerThread(client1, client2);
			serverTh.start();
			System.out.println("Der Server ist gestartet...");
		}
	}
	
	public static void main(String[] args) {
		if(args.length == 1)
		{
		try {
			server = new ServerSocket(new Integer(args[0]).intValue());
			new Server ();
			System.out.println("Listen to port: "+ server);
		} catch (IOException e){
			System.out.print(e);
		}
		}
	}
}
```

Ich hoffe mir kann jemand helfen... Vielen Dank schonmal im Vorraus!!!


----------



## SlaterB (25. Nov 2010)

das Problem ist dass du im Client mehrere Streams hast, die auf dem server.getInputStream() lesen,
besonders gemein ist der BufferedReader, der liest nämlich nicht nur eine Zeile, sondern soviel wie irgendmöglich geht, 
und auch das false kommt dann dort rein, zu testen mit


```
str = str.replace(str.charAt(0), " ".toCharArray()[0]);
			System.out.println(str);
			System.out.println("Checkpoint 1");
			System.out.println("noch im Buffer: "+input1.read());
			System.out.println("Checkpoint 1.1");
			finish = input.readBoolean();
```
für den readBoolean()-Aufruf sind jedenfalls keine Daten mehr da, dieser Aufruf wartet ewig,

----
wenn du
> System.out.println("noch im Buffer: "+input1.read());
wieder rausnimmst könnte es mit dem restlichen Stand für die normalen Spielrunden gut gehen, wenn du im Server zwischen Senden des Textes und False bzw. True eine Pause einlegst, z.B.
Thread.sleep(500);
dann wird der BufferedReader nur die Textzeile bekommen, der Boolean landet an der richtigen Stelle

am Ende des Programms wird es noch Fehler geben weil du dort zu schnell close() aufrufst glaube ich,
erstmal die Infos zum Spielende senden und den Clients Zeit geben zum Empfang, dann close(), oder die Clients sollen jeweils closen() wenn keine Kommunikation mehr ansteht

--------

BufferedReader + DataInputStream gleichzeitig ist generell schlecht, entscheide dich für eins von beiden,
ich persönlich empfehle nur BufferedReader mit Zeilenumbruch senden und readLine(),
dann weißt du immer wieviel du senden und wieviel du emfangen wirst,
Zahlen oder die boolean-Information kannst du auch in einer String-Zeile unterbringen
(edit: das Thread.sleep(500); kann dann weg)

zum Senden auch nur BufferedWriter, keinen DataOutputStream

genauso empfehle ich aus System.in mit BufferedReader zu lesen, das ist dann schön einheitlich,
wenn der User Enter drückt, dann mit readLine() genau eine Zeile lesen, 
ob das Text oder ein Zahl ist kann man alles aus dem String parsen, Scanner sieht schön aus, hat aber Macken


----------



## Chumax (25. Nov 2010)

zu langsam


----------



## SlaterB (25. Nov 2010)

tjaja, ich muss auch mal was lösen


----------



## Miramizu (25. Nov 2010)

Also bei mir klappt das immernoch nicht, und wo ich das sleep einbauen soll verstehe ich auch nicht, und wieso ich nur eins verwenden soll ist mir auch nicht klar... im grunde weiß ich nicht, wie ich das jetzt abändern müsste... jedenfalls funktioniert es leider immernoch nicht... könnt ihr mich vll sagen in welcher zeile ich was einfügen soll?

oder mach ich irgendwas falsch... ich bin noch anfänger, besonders auf dem gebiet von netzwerken, deswegen ist das für mich noch ein buch mit sieben siegeln...

hier nochmal meine codes:
[edit SlaterB: komplette Wiederholung der Codes ohne Hinweis auf Änderungen entfernt]


----------



## SlaterB (25. Nov 2010)

> wo ich das sleep einbauen soll verstehe ich auch nicht



SlaterB hat gesagt.:


> wenn du im Server zwischen Senden des Textes und False bzw. True eine Pause einlegst, z.B.
> Thread.sleep(500);
> dann wird der BufferedReader nur die Textzeile bekommen, der Boolean landet an der richtigen Stelle


dieser Satz ist dir unklar?
du kannst nicht erkennen, welche Stelle im Server Text sendet und welche wenig später 'false/true' sendet?

das ist ja nicht zu akzeptieren, allein eine Textsuche nach 'false' bzw. 'true' liefert nur genau eine Stelle in den Serverklassen,
davor eben..

------

zu den Streams habe ich alles gesagt was ich dazu sagen kann, wiederholen werde ich es nicht,
man braucht da natürlich gewisse Grundkenntnisse,
eine ganz einfache Regel ist: getXYStream() vom Socket oder irgendwoher nur genau EINMAL für einen weiteren Stream verwenden, nicht ZWEIMAL oder öfter


----------



## Michael... (25. Nov 2010)

SlaterB hat doch schon darauf hingewiesen, dass das Problem darin liegt, dass Du im Client den InputStream mit mehreren Readern ausliest. ==> der eine Reader schnappt sich, das für den zweiten Reader bestimmte Paket ==> der zweite Reader wartet vergebens und blockiert.

Grundsätzlich ist Dein Code und Klassenaufbau nicht gerade schön, den Thread im Server könntest Du Dir sogar sparen, da Du sowieso alles darin ablaufen lässt.
Empfehlung: Fange mit einer einfachen Client-Server-Architektur an.


----------



## Miramizu (25. Nov 2010)

Okay, okay, ich werde es gleich nochmal probieren, vielen Dank übrigens 


Ja ne einfach Server Client Sache wäre natürlich besser, aber das ist ja eine Aufgabe vom Studium, da habe ich nicht wirklich viele Freiheiten, heißt ich muss einen Thread verwenden... Übrigens sind das meiste da drin Vorgaben, die wir nicht einmal selbst erstellen mussten, deswegen ist es ja so schwieirg nachzuvollziehen... Im Grunde hab ich nur das Spiel gemacht, das andere war schon... Eine von diesen sinnvollen Aufgaben eben  

Jedenfalls vielen Dank, ich probiere es heute Nachmittag nochmal, falls ich danach immernoch Probleme haben sollte, melde ich mich nochmal


----------



## Michael... (25. Nov 2010)

Im Server-Client-Bereich machen Threads ja auch Sinn - aber nur wenn man sie sinnvoll einsetzt ;-)


----------



## Miramizu (25. Nov 2010)

okay also wenn ich diese zeile im serverthread seinsetze, kommt eine fehler meldung... ich verstehe es wirklich nicht, so leid es mir tut...


----------



## SlaterB (25. Nov 2010)

dir sollte nix leid tun, stattdessen die Energie ins Denken investieren, 
z.B. daran denken, in solchen Problemfällen immer die Fehlermeldung zu posten,
das ist doch nicht schwer, oder?

wahrscheinlich musst du noch eine mögliche Exception-Art abfangen, am Ende des Serverthreads hast du schon
>   } catch(IOException e){
ändere das in 
>   } catch(Exception e){
dann fängst du alle möglichen Exceptions ab, dann müsste der Compiler Ruhe geben


----------



## Miramizu (25. Nov 2010)

JUHU Die Durchgänge funktionieren endlich 

Allerdings gibt es noch einen Fehler, wenn jemand zwiemal gewonnen hat, soll das Spiel bereits stopppen, also dass es mind zwei und höchstens 3 Durchgänge hat... Wenn das behoben wäre wäre es perfekt... schonmal vielen Dank!!!!

Interessant ist, dass niemand das Problem gesehen hat, also hier in FH


----------



## Miramizu (25. Nov 2010)

okay also gut jetzt läuft es auch nach 2 durchgängen ab, die clients schließen, aber der server is noch aktiv, den muss ich manuell abbrechen... wie kann ich das machen, dass er sich am ende selber schließt?


----------



## SlaterB (25. Nov 2010)

System.exit(0);


----------



## Miramizu (25. Nov 2010)

Okay ein neues Problem ist aufgetreten. Nachdem ein Spieler zweimal gewonnen hat hört das Spiel auf, aber er printet nicht "Sie haben das Spiel gewonnen/verloren"... Das ist beim Serverthread ab Zeile 25, diese Anweisung wird nciht durchgeführt, stattdessen steht beim Verliere des Spiels einfach nur "null", und beim Gewinner kommt in der Konhsole folgende Meldung: "java.io.EOFException"

verändert an den Codes wurde bis jetzt eben das, was mit empfohlen wurde.


----------



## Miramizu (25. Nov 2010)

mir fällt gerade ein, dass ich an den zahlen etwas verändetr haben:


```
if(indexclient1 < 3 && indexclient2 < 3 )

				{
					Thread.sleep(500);

					output1.writeBoolean(false);

					output2.writeBoolean(false);

					System.out.println("False");

					output1.flush();

					output2.flush();

				}

				else

				{
					Thread.sleep(500);

					output1.writeBoolean(true);

					output2.writeBoolean(true);

					System.out.println("True");

					output1.flush();

					output2.flush();

				}

				

				System.out.println("Checkpoint 3");

			}while(indexclient1 < 3 && indexclient2 < 3);

				System.out.println("Checkpoint 4");

			

				if(indexclient1 == 2)

				{

					output1.writeChars("Sie haben das Spiel gewonnen !\n");

					output2.writeChars("Sie haben das Spiel verloren !\n");

				}

				else if(indexclient2 == 2)

				{

					output2.writeChars("Sie haben das Spiel gewonnen !\n");

					output1.writeChars("Sie haben das Spiel verloren !\n");

				}
```

so jetzt


----------



## SlaterB (25. Nov 2010)

zum Spielende hatte ich ja bereits geschrieben


SlaterB hat gesagt.:


> am Ende des Programms wird es noch Fehler geben weil du dort zu schnell close() aufrufst glaube ich,
> erstmal die Infos zum Spielende senden und den Clients Zeit geben zum Empfang, dann close(), oder die Clients sollen jeweils closen() wenn keine Kommunikation mehr ansteht


ein sleep(500) kann da auch helfen


----------



## Miramizu (25. Nov 2010)

Hmm... Wo muss ich denn den sleep() einbauen, und wie sieht da die Syntax aus? muss ich da Client.sleep(500); schreiben, oder wie?

Aber muss schon beim Client eingebaut sein, oder?

Irgendwie kommt nämlich immernoch null, nach zwei Spielen, aber nach 3 steht dann das richtige da... unverständlich für mich...


----------



## SlaterB (25. Nov 2010)

wie nach 2/ nach 3 Spielen?, ich denke es geht um das Ende wenn nur noch "Sie haben das Spiel gewonnen/verloren" geschrieben wird und Programmende?
da kann doch nicht noch ein Spiel kommen

welches sleep gemeint ist darfst du raten, wobei ich den Tipp gebe, dass es in diesem Thema schon früher als Vorschlag von mir vorkam..
es gibt auch quasi nur ein sleep() in Java, das grenzt es vielleicht noch mehr ein


und wo es hinkommt ist wiederum 'eigentlich' eindeutig:
ich sage dass du zu schnell close() nach der letzten Ausgabe (die ja "Sie haben das Spiel gewonnen/verloren" ist) ausführst,
also muss das Warten zwischen dieser Ausgabe und dem close() stehen, scheint so einfach..


----------



## Miramizu (25. Nov 2010)

Ich habe das Spiel so programmiert, dass es zu ende ist, wenn jemand2 matches gewinnt. wenn 3 matches stattfinden, also jeder gewinnt mind einmal, dann funktioniert die ausgabe "Sie haben das Spiel gewonnen/verloren".

Wenn aber jemand sofort zweimal gewinnt, steht da plötzlich "null".

ich dachte ich muss das sleep in die Client klasse einbauen und wenn ich das tue, kommt beim compilieren folgende fehlermeldung:
Client2.java:52: cannot find symbol
symbol  : method sleep(int)
location: class Client2
                Client2.sleep(500);
                       ^
1 error


----------



## SlaterB (25. Nov 2010)

das mit 2x/3x ist erstaunlich, wenn der Fehler noch nicht weggeht, dann poste bitte dein aktuelles Programm

wie du auf den Client kommst ist mal wieder fraglich da ich eigentlich die ganze Zeit vom Server spreche oder zumindest die Stelle, an der close() ausgeführt wird, aber nun gut, das passiert im Client auch

Server:

```
[..]
 else if(indexclient2 == 2)
                {
                    output2.writeChars("Sie haben das Spiel gewonnen !\n");
                    output1.writeChars("Sie haben das Spiel verloren !\n");
                }
            output1.flush();
            output2.flush();
            System.out.println("Checkpoint 5");
            Thread.sleep(500); // Zeit geben, die Nachricht zu übertragen, bei close() liest der 
            // Client die letzte Nachricht nicht mehr unbedingt, vielleicht sender der Server bis dahin 
            // auch gar nicht, aber teils Vermutung, nicht genau getestet
            [diverse close();]
```


----------

