# Probleme bei Messenger



## Maxim6394 (13. Dez 2011)

ich schaff es irgendwie nichts das ding zum laufen zu bringen. ich hab hier eine serverklasse die 2 mal auf einen client wartet der sich verbindet. danach sollte durch nen buttonclick testweise eine nachricht verschickt werden. hier der code:


```
public void run()
	   { 
		   
		   try{
			  
				   
			        	  Socket client_socket = listen_socket.accept();      
			                Connection peer = new Connection(client_socket,clients);
			                connections.add(peer);
			               peer.send("socket connected digga");
			    
					          for(Connection cl :connections)
					          {
					        	  
					        		  cl.send("1 clients connected");
					        	  
					          }
					          
					          
					          System.out.println("client 1 connected");
					          
					          
					    	  Socket client_socket_02 = listen_socket.accept();      
				                Connection peer_02 = new Connection(client_socket_02,clients);
				                connections.add(peer_02);
				               peer.send("socket connected digga");
				          
				       
						          for(Connection cl :connections)
						          {
						        		  cl.send("2 clients connected");				        	  
						          }
		
						          System.out.println("client 2 connected");
					          
					          while(true)
							   {
					
			          int i=0;
			          for(Connection c :connections)
			          {	 
			        	  if(c.client.isConnected())
			        	  {
			        		  i++;
			       
			        	  }
			          }
			          clients=i;
			      
			       
					       for(Connection c :connections)
					          {
					    	
					        	  if(c.client.isConnected())
					        	  {
					        		  for(Connection c1:connections)
					        		  {
					        			  if(c1.getMessage()!=null)
					        				  c1.send(c.getMessage());
					        				  System.out.println(c.getMessage());
					        		  }
					        		
					        		
					        	  }
					          }
```





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

public class Connection extends Thread 

{

	public Socket client;
	public BufferedReader in;
	public PrintWriter out;
	public int clientNr;
	

	public Connection(Socket client_socket,int nr)
	{
		
		
		System.out.println("connection class created");
		client=client_socket;
	
		clientNr=nr;
		
		
		
		try
		{
			
			 out=new PrintWriter(
					client_socket.getOutputStream(),true
				);
		
		 in=new BufferedReader(
				new InputStreamReader(
						client_socket.getInputStream()
						)
				);

	    
		 
		}catch(IOException e){  
			
			System.err.println("Exception while getting socket streams: " + e);}
			
	
			this.start();
	
	}

	public void send(String msg)
	{
		out.println(msg);
	}
	
	
	public String getMessage()
	{
		try{
			String text=in.readLine();
			if(text!=null)
			{			
				 System.out.println("text:"+text);
				 
			}
			 
			return text;
			
		}catch(IOException e){ }
	
	return null;
	}
	public void run()
	{

	while(true)
	{

		
	}
		
	}
	
}
```

kann mir einer sagen was da falsch ist?

bis jetzt wird jedenfalls bei nem click des buttons, nachdem 2 clients geöffnet wurden, eine nachricht zum fenster des anderen geschickt, aber das passiert irgendwie nicht immer. es reagiert immer nur eins der fenster wenn man etwas zum anderen schicken will, bis man ein par mal auf den button gehämmert hat, dann reagiert wieder nur der im anderen client.


----------



## irgendjemand (13. Dez 2011)

ganz erlich ...
wenn du deinen code nicht mal ordentlich formatiert ... und dann für java code nicht mal java-tags nimmt ... dann hab ich auch keine lust mir das durchzusehen ...

aber das hier

```
public void run()
{
	while(true)
	{
	}
}
```
hat 1) keinen sinn und 2) lastet es die cpu des servers aus ...


auch finde ich den ansatz schon falsch explizit auf zwei verbindungen zu warten ...
bau das ganze lieber als uni-connect system ... also das du in einem loop generell auf verbindungen wartest ...


sehr einfaches beispiel hier : Kaffee & Kuchen - Datenbank-Anbindung mit JDBC


----------



## Kr0e (14. Dez 2011)

nimm nio oder aio. alles andere ist post-mortem. Netty3 (bald 4) ist zu bevorzugen!


----------



## irgendjemand (14. Dez 2011)

ja klar sind nI/O und aI/O deutlich zu bevorzugen ... aber der link den ich gepostet habe kommt dem wissensstand von TO nahe ... wobei nI/O und vorallem aI/O diesen deutlich übersteigen würden ...

*ich geb zu ... nI/O geht langsam bei mir ... aber aI/O ist auch für mich noch viel zu lernen xD


----------



## Maxim6394 (16. Dez 2011)

ich hab hier wieder ein kleines problem bei einer server-client anwendung.
ich hab ne while schleife beim server die endlos läuft und immer den input vom client aufnimmt. 
wenn jetzt der client aber disconnectet und dann wieder connectet, kommt der fehler hier:

```
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
	at java.util.ArrayList$Itr.next(ArrayList.java:791)
	at Server.run(Server.java:68)
	at Server.main(Server.java:103)
```


```
public void run()
{
	try{
		while(true)
		{
			
	
			for(Connection client:peers)  //zeile 68
			{
			
				if(client.client.isConnected())
				{
				
			
					String msg=client.in.readLine();
					if(msg!=null)
					{
						print(msg);
					}
					
				}
					
			}

		}
	
	
	}catch(IOException e){}
```

client ist eine klasse in der input und output stream und der socket drinne sind. client.client ist der socket.
hab auch versucht vorher in einer while schleife alle zu entfernen die nicht connectet sind, aber geht nicht.


----------



## Kr0e (16. Dez 2011)

Das heißt, dass du den Inhalt deiner Liste änders, während du iterierst. for(... : ...) erstellt intern einen Iterator und wenn du also den Clienten innerhalb der for-schleife entfernst , dann kommt beim nächsten durchgang eine concurrentmodified excetion...


----------



## irgendjemand (16. Dez 2011)

auch sieht das ganze sehr unsauber aus ...

soweit man den code hier lesen kann wird auch ein "toter" client nicht aus der liste entfernt *zumindest nicht in dem code den du gepostet hast* ... und das führt sehr schnell zu nem speicher-leak da du deine liste mit immer mehr "toten" verbindungen zumüllst ...

@Kr0e
da muss ich dich berichtigen ...

wenn du ein foreach schreibst wird da kein richtiger iterator verwendet ...
der compiler baut ein "normales" for() mit counter draus *vergleich output von JAD-decompiler*

mag sein das ein JIT da dann doch wieder ein iterator draus macht ... aber der bytecode selbst enthält nach dem compilen nur ein normales for() ... weder das foreach noch einen Iterator


----------



## Kr0e (16. Dez 2011)

Vorsicht!

Es stimmt, es wird ein normales for draus gemacht, aber keins mit int index und normalen hochzählen. Das wäre zu unperformant. Denke man an eine LinkedList. Wenn dort altmodisch mit einem int index jede Position abgefragt wird, so wird das ziemlcih schnell unperformant. Es wäre auf jeden Fall nicht mehr O(n)!


foreach wird in etwa so umgeformt werden:

String s;
for(Iterator<...> it = list.iterator; it.hasNext(); s = it.next()) {

   // iwas mit machen..
}


Übrigens, dass ist einer der Gründe, warum manche Listen z.b. das Interface "RandomAccess" implementieren. Z.b. die ArrayList. 


Und noch ein ARgument für meine Seite: foreach klappt generell nur wenn der Datentyp das Interface

Iterable implementiert. (Schau dafür in die Doku, wdort wird das erläutert und vor allem der Zusammmenhang mit foreach).

Gruß,
Chris


PS: Hmmm, ich gebe zu wenn ich mich irre. Obwohl es die Doku sagt, wird trotzdem keine Concur... geworfen. DAs wundert mich. Nagut, sorry, mein Fehler. Hatte ich anders in ERrinnerung!


Obwohl ich es nicht verstehe, folgendes erzeugt keinen Fehler:


```
List<String> strings = new LinkedList<String>();
		Collections.addAll(strings, "1", "2", "3");

		try {
			for (String s : strings) {
				if (s.equals("2")) {
					strings.remove(s);
				}
				System.out.println(s);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
```


Wobei das hier auch zu seltsamen Ergebnissen führt: Z.B. wird nur 1 und 2 auf der Konsole ausgeben. Anscheinend ist das irgendeiner Art Iterator, der sich die Positoin merkt, aber keinerlei ÜBerprüfungen bzg. der Modifizierung macht, so wie normale Iteratoren. Sehr kmisch!



EDIT:

Noch einen Test gemacht:


```
Set<String> strings = new HashSet<String>();
		Collections.addAll(strings, "1", "2", "3");

		try {
			for (String s : strings) {
				if (s.equals("2")) {
					strings.remove(s);
				}
				System.out.println(s);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
```

Hier ist der Output:


3
2
java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
	at java.util.HashMap$KeyIterator.next(HashMap.java:828)
	at de.probst.AppStart.main(AppStart.java:136)


....

Komisches Verhalten, vorallem da nicht vorhersehbar und unterschiedlich!


----------



## Maxim6394 (17. Dez 2011)

wie kann ich dann die client die nicht mehr verbunden sind aus der arraylist löschen?

übrigens kommt da auch diese verdammte exception wenn ich mehrere clients mit dem server verbinde und dann etwas sende. diese for schleife wird dabei auch wieder als fehlerhaft angezeigt.


----------



## Kr0e (17. Dez 2011)

Du kölnntest es so machen : Du erstellst jedes Mal eine Kopie der Liste und gehst diese durch. Löschen tust du die CLienten dann aus der originalen Liste. Wenn eine ArrayList benutzt, ist das Kopieren quasi null-Aufwand, da der Speicher intern einfach nur dupliziret wird. Selbst Listen mit Millionen von Einträgen werden in wenigen ms kopiert.... Besser wäre allerdings manuell einen Iterator zu erstellen und dann ggf. die remove(); Funktion benutzen. Aufpassen: Hier sind ArrayListen sehr unperformant, nimm dann lieber eine LinkedList!

Achja, ich kenne ja jetzt nicht deinen kompletten Code, aber das Löschen der Clienten solltest du je nachdem synchronisieren! Sprich wenn ein Client stirbt, vlt. einen "Remove Client REquest" in eine Queue einreihen und später löschen. Falls derweil auf den Clienten zugegriffen wird, einfahc mit Status-flags arbeiten, nach dem Motto "Client ist tot aber noch in Liste". Das wäre alles etwas anders mit NIO/AIO, da du dort konsistente Threading Modells nutzt (Bzw. wenn du es richtig mcahst uind die Vorteile von NIO verstehst  ).

Gruß,
Chris


----------



## Marcinek (17. Dez 2011)

Um einen Client aus der Liste zu löschen brauchst du doch nicht die Liste durchzueghen.

ArrayList() kann auch einfach remove(Client) machen.

Ansonsten kannst du auf dem Iterator remove() aufrufen. dieser entfernt das aktuelle Objekt aus der Liste ohne o.g. Exception.


----------



## Maxim6394 (17. Dez 2011)

aber wieso kommt diese exception auch wenn ich mir nur von jedem client den inputstream hole? bei einem client geht es, bei mehreren nicht.


----------



## Maxim6394 (17. Dez 2011)

ich hab jetzt mal versucht für jeden client der connectet einen neuen thread zu erstellen. hier der code:


```
while(true)
					{
			
		
						try{
					if(serverSocket!=null)
					{
						Socket client=serverSocket.accept();					
		
						print(".");
						clientThreads.add(new clientThread(client));
			
						print("..");
						print("peers:"+clientThreads.size());
			
						print("client connectedasdf ");
					}	
				}catch(IOException e){}
				
					}
```


```
class clientThread extends Thread
{
	
	PrintWriter	out;
	BufferedReader in;
	Socket client;
	
	public clientThread(Socket s)
	{

		try{
		client=s;
		 out=new PrintWriter(
					client.getOutputStream(),true
				);
		
		 in=new BufferedReader(
				new InputStreamReader(
						client.getInputStream()
						)
				);
		print("client connected");
		

		print("peerssize:"+clientThreads.size());
		
		run();
		
	} catch (IOException e) {System.err.println("connection problem");}
	}
	
	public void run()
	{
	
	
		try{
			while(true)
			{
			print(clientThreads.size());
				
			String text=in.readLine();
			if(text!=null)
			{
				print(text);
			}
			}
		}
		catch(IOException e){};
		
	}
	
	
	
}
```

bei einem einzigen client werden die nachrichten korrekt ausgegeben, bei allen die danach connecten gibts keine reaktion.


bei dem code oben wird der eine punkt ausgegeben. alles was danach kommt nicht. wieso?
und außerdem wird bei 	print("peerssize:"+clientThreads.size()); 0 ausgegeben. wie kann das sein? ich erstelle eine neue instanz davon doch direkt in dieser arraylist drinne.


----------



## Maxim6394 (17. Dez 2011)

selbst wenn ich das ganze zeug mit den arraylists weglasse und einfach ein neues clientThread objekt erstelle, der server bekommt nur die nachrichten vom ersten client der connectet hat, von allen anderen kommt überhaupt nichts rein.


----------



## Marcinek (17. Dez 2011)

Kannst du mal dein projekt ir schicken oder es hier hochladen?

axo mit run() kannst du keinen thrad erzeugen


----------



## Maxim6394 (18. Dez 2011)

also ich hab jetzt jetzt geschafft mehrere clients zu connecten, aber ich kriegs nicht hin die nicht mehr verbundenen zu entfernen.
ich hab versucht die arraylist wo alle drin sind an die clientThread klasse zu übergeben, dann mit isClosed() die ganze zeit abfragen ob das socket geschlossen ist, wenn ja dann aus der arraylist löschen. die bedingung ist aber irgendwie nie erfüllt. mit isConnected()==false hab ichs auch versucht, geht nicht.

außerdem hab ich noch versucht eine string überprüfung zu machen, also von dem text der vom client zum server reinkommt.
der client sendet zum beispiel den text "text". ich frage dann im input stream ab ob das was reinkommt =="text" ist. das ist aber immer false.
wie kann das sein?

hier das was der client sendet:

```
out.println("text");
```

das ist dann beim server:


```
if(text!=null)
				{
					
					if(text=="text")
					{
				
					print("bedingung erfüllt");
					}
					else
					{
						print("nicht erfüllt");
                                               print(text);

					}
				}
```

dabei ist die bedingung nicht erfüllt, obwohl der client doch genau "text" sendet. das gleiche wird dann auch ausgegeben.


----------



## Kr0e (18. Dez 2011)

Beschäftige dich nochmal mit den Grundlagen, dir fehlt offenbar eine Menge...


----------

