Localhost - ok, ip - fast ok

Also ich habe dein Beispiel mal bei mir getestet und kann dir sagen, dass es bei mir sowohl mit Locolhost und meiner Ip- Adresse im localen Netzwerk läuft, daher macht es bei mir keinen Unterschied. Daher würde ich die Probleme nicht bei dem fehlendem Close sehen, sondern bei deinen PC/Router Einstellungen.

Bei den NAT-Einstellungen kann man nichts falsch machen. Es geht oder es geht nicht. Mehr Optionen sind da nicht vorhanden. In dem Moment wo von Extern die Verbindung aufgebaut wurde, sind die NAT-Einstellungen richtig.

also mal von abgesehen das das mal wieder so ein „ich steck alles in ein file und scheiß auf programm-logik“-code ist macht mich eine zeile dann doch ganz besonders unruhig : if(BufferedReader.ready())
ich zitier mal die DOC

public boolean ready() throws IOException

Tells whether this stream is ready to be read. A buffered character stream is ready if the buffer is not empty, or if the underlying character stream is ready.

Overrides: ready in class Reader

Returns: True if the next read() is guaranteed not to block for input, false otherwise. Note that returning false does not guarantee that the next read will block.

Throws: IOException - If an I/O error occurs

oder um es einfach zu sagen : ich vermute einfach mal das BufferedReader.ready() false liefern wird … dadurch hängt die CPU in einem LEEREN loop drin (was dann mal eben 100% CPU-last verursacht) und dürfte probleme haben sich irgendwann mal wieder zu fangen … und das delay was entsteht wenn dein system das erst übers netz an den router geben muss um es von dort wieder zu empfangen reicht halt aus das die CPU sich festfrisst

am besten ist du machst folgendes

  1. das if komplett raus … is doch egal ob readLine() blockt oder nicht … wichtig ist nur das InputStream.read() überhaupt aufgerufen wird
  2. falls das immer noch nicht ausreicht baue in den read-loop am ende noch ein sleep(10) oder so ein … das reicht schon um die CPU wieder aus deinem loop rauszubekommen und ihr genug luft für andere dinge zu geben … was dann die auslastung auch von 100% auf 0% oder 1% senken dürfte

ansonsten noch ein allgemeiner rat : versuch nicht alles krampfhaft in einander zu schachteln, halte den code lieber leserlich und hau hier und da mal die eine oder andere debug-ausgabe oder ein kurzes sleep() mit rein …

und das dein anderer code auch nicht so richtig will lässt drauf schließen das dort ähnliche fehler enthalten sind
hier mal ein funktionsfähiger code

import java.net.*;
import java.util.*;
public class Server
{
	private ServerSocket serverSocket=null;
	private ArrayList<ClientRunnable> clients=null;
	private static Server server=null;
	public static void main(String[] args)
	{
		System.out.println("start-up chat-server");
		server=new Server();
		server.startup();
		System.out.println("start-up complete");
	}
	private Server()
	{
		System.out.print("try to create ServerSocket ... ");
		try
		{
			serverSocket=new ServerSocket(12345);
		}
		catch(Exception e)
		{
			System.out.println("failed to create ServerSocket");
			e.printStackTrace();
			System.exit(1);
		}
		System.out.println("ok");
		clients=new ArrayList<ClientRunnable>();
	}
	private void startup()
	{
		System.out.print("setting up accept-thread ... ");
		Thread thread=new Thread(new Runnable()
		{
			public void run()
			{
				while(true)
				{
					try
					{
						Socket client=serverSocket.accept();
						ClientRunnable clientRunnable=new ClientRunnable(server, client);
						(new Thread(clientRunnable)).start();
						clients.add(clientRunnable);
					}
					catch(Exception e)
					{
						System.out.println("failed to accept client");
						e.printStackTrace();
					}
				}
			}
		});
		System.out.println("ok");
		System.out.println("starting accept-thread");
		thread.start();
	}
	protected void broadcast(String msg)
	{
		for(ClientRunnable client : clients)
		{
			client.send(msg);
		}
	}
	protected void disconnect(ClientRunnable client)
	{
		clients.remove(client);
	}
}```
```import java.io.*;
import java.net.*;
class ClientRunnable implements Runnable
{
	private Server server=null;
	private Socket socket=null;
	private BufferedReader in=null;
	private PrintStream out=null;
	protected ClientRunnable(Server server, Socket socket)
	{
		this.server=server;
		this.socket=socket;
	}
	public void run()
	{
		try
		{
			in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out=new PrintStream(socket.getOutputStream());
		}
		catch(Exception e)
		{
			System.out.println("cant get client-streams");
			e.printStackTrace();
			return;
		}
		String line="";
		while(true)
		{
			try
			{
				line=in.readLine();
				if(line==null)
				{
					break;
				}
				if(line.equals(""))
				{
					continue;
				}
				if(line.equals("DC"))
				{
					break;
				}
				server.broadcast(line);
			}
			catch(Exception e)
			{
				System.out.println("failed to read message");
				e.printStackTrace();
			}
		}
		try
		{
			in.close();
			out.close();
			socket.close();
		}
		catch(Exception e)
		{
			System.out.println("cant close streams/socket");
			e.printStackTrace();
		}
		server.disconnect(this);
	}
	protected void send(String msg)
	{
		try
		{
			out.println(msg);
		}
		catch(Exception e)
		{
			System.out.println("cant send message");
			e.printStackTrace();
		}
	}
}```
```import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ClientApplet extends JApplet
{
	private Socket socket=null;
	private BufferedReader in=null;
	private PrintStream out=null;
	private JTextField jTextField=null;
	private JTextArea jTextArea=null;
	public ClientApplet()
	{
		setLayout(new BorderLayout());
		setBackground(Color.LIGHT_GRAY);
		setForeground(Color.BLACK);
	}
	public void init()
	{
		jTextField=new JTextField();
		jTextField.setBackground(Color.WHITE);
		jTextField.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				try
				{
					String msg=jTextField.getText();
					if(!msg.equalsIgnoreCase("DC"))
					{
						out.println(msg);
					}
					jTextField.setText("");
				}
				catch(Exception ex)
				{
					jTextArea.append(ex.toString()+"
");
				}
			}
		});
		jTextArea=new JTextArea();
		jTextArea.setBackground(Color.WHITE);
		jTextArea.setEditable(false);
		this.add("South", jTextField);
		this.add("Center", jTextArea);
	}
	public void start()
	{
		try
		{
			socket=new Socket(this.getCodeBase().getHost(), 12345);
			in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out=new PrintStream(socket.getOutputStream());
		}
		catch(Exception e)
		{
			jTextArea.append(e.toString()+"
");
			jTextArea.append("cant connect to server");
			return;
		}
		jTextArea.append("connected
");
		(new Thread(new Runnable()
		{
			public void run()
			{
				String line="";
				while(true)
				{
					try
					{
						line=in.readLine();
						if(line==null)
						{
							break;
						}
						if(line.equals(""))
						{
							continue;
						}
						jTextArea.append(line+"
");
					}
					catch(Exception e)
					{
						jTextArea.append(e.toString()+"
");
					}
				}
				jTextArea.append("ERROR");
				try
				{
					in.close();
					out.close();
					socket.close();
				}
				catch(Exception e)
				{
					jTextArea.append(e.toString()+"
");
				}
				return;
			}
		})).start();
	}
	public void stop()
	{
	}
	public void destroy()
	{
		try
		{
			out.println("DC");
			in.close();
			out.close();
			socket.close();
		}
		catch(Exception e)
		{
			jTextArea.append(e.toString()+"
");
		}
	}
}```
du solltest vorher aus dem applet vielleicht noch eine swing-app machen und dem socket-konstruktor was sinnvolles übergeben ... der code stammt noch aus zeiten des 1.7.0_05 ...
wenn auch DAS nicht hinhaut hast du entweder ein richtiges problem in deinem netzwerk, irgendwas an deinem OS ist ziemlich kaputt oder du hast sogar ein hardware-problem ... (ich habs grade noch mal unter 1.7.0_51 getestet : läuft

wenn du willst kann ich dir auf meinem server auch einen einfachen ping-service anbieten der dann versucht dich eingehend zu erreichen und dir nachrichten zu schicken ... musst nur sagen

generell ist sowieso ersteinmal verläßlicher Standardcode aus dem Internet zu testen,
das eigene Programm komplett ignorieren vorerst,
Funktionalität des Netzwerks mit Java-Sockets feststellen

hatte ich mehr oder weniger auch schon genannt, vielleicht noch nicht so deutlich

Danke erstmal.
Ja der code ist schei**e aber der sollte eben mal schnell repräsentieren wie ich es dort auch mache.

Ch werde deinen code mal testen, das problem ist aber - die diskussion hatten wir schonmal - das ich ja mehrere clients haben kann, (sinnvollerweise), und deshalb nicht bei read () blocken kann. Wenn es dann bei einem spieler lurz laggt wuerde es bei allen laggen. Und ich wollte nicht fuer jeden spieler einen eigenen thread oeffnen…
Da bin ich aufs ready () gekommen… gibt es da weitere moeglichkeiten?

wie gesagt 10 ms warten nach z.B. einer Runde alle Clients (erfolglos) abklappern,
das macht angesichts von Netzwerkübertragungszeiten fast nichts aus und die Anzahl der Schleifendurchläufe verrringert sich von Mio./ Mrd. pro Sekunde auf 100,
ein CPU-Kern von 100% auf nahe 0%,
wobei das eher die Sichtweise arg träger System wie ein Forum oder eine Swing-GUI ist, meist sekundenlang und lnger nichts los,

‘kurz laggt’ klingt ja nach ständiger Übertragung, da sieht es bisschen anders aus, 10ms könnten da auch schon stören,
evtl. auch 1 ms oder ähnliches warten, je nach Genauigkeit welcher ich immer (noch) misstraue,

überhaupt auch nebenher mitzählen, wie viele Schleifendurchläufe gibt es, wie viele Nachrichten,

Grundsätzlich wird jede Verbindung -jeder Client- in einem eigenen Thread bearbeitet. Das ist echt Socket 1x1 wie auch oben im Post von Herrn Unregistriert zu sehen, falls du dir den durchgelesen hast… Dadurch ist es völlig in ordnung dass das read blockiert, es wird ja nur der jeweilige Thread blockiert der mit dem einen Client kommuniziert.

Ja den Post hatte ich gelesen, frage mich gerade ob du meinen letzten Post gelesen hast.
Ich dachte nämlich nicht das bei 10 Spielern 10 Threads eine lösung wären, bei minecraft und 500 spielern
500 Threads.
Der Thread den ich deshalb eröffnet hatte, bzw der Post der eurere Meinung gleichkommt:

link

Was spricht denn gegen 500 Threads?

[quote=Prototype]Edit: Man macht natürlich keine 50 Threads auf. Der Scheduler ist dann praktisch nur noch mit dem switching der Threads beschäftigt.[/quote]…

Was aber nur eine Pauschalaussage ist - das trifft nur zu wenn die Threads zu 100% die CPU foltern UND die Thread nahe zu nix machen aus mal kurz eins zwei zahlen zu addieren. Ist aber ein Thread im Idle (weil sleep()) bzw. Blocking (weil read()), passiert gar nix.

Aktuell laufen hier 128 Programme mit gesammt 314 Threads. Load Average 0.15;
Anderer Rechner: 136 Programme mit 297 Threads. load Average 1.07;

qed

Anders ausgedrückt, was soll ein Scheduler denn sonst noch machen außer Threads zu switchen?

Hm
Ich glaube ihr habt mich überzeugt, ich versuchs so mal. Aber das ändert erstens nichts an meinem Problem und zweitens… hab ich nichts. ^^
Ich dacht einfach immer “Multithraeding - ja, aber das heißt nicht joa machen wir mal 500 Threads auf…”
Vor allem bei einem grafisch basierten Spiel ist es ja so, das diese Operation quasi FPS mal in einer Sekunde passieren SOLLTE…
Aber naja, ein oder zwei versuche ist es Wert.

Wenn du über 100 Clients gleichzeitig kommunizieren lassen willst wird’s sowieso notwendig sich über Skalarisierbarkeit Gedanken zu machen. Sprich das Programm so konstruieren, dass man nicht unbedingt auf einen Server festgelegt ist, sondern noch einen oder mehr hinzuschalten kann. Dass sowas mit deiner alten Lösung nicht geht sollte klar sein. Ich weis nicht wieso du denkst dass Threads den Rechner so ausbremsen sollten… die CPUs bekommen doch immer mehr Kerne, die verdoppeln sich doch auch schon alle Jahre oder so.

Thread switchen - dafür ist er ja da. Nur werden die Threads nicht permanent geswicht, sondern wenn sie im WAITING sind.

Der - die auf Multicore - Thread wechseln von RUNNING in WAITING, wenn der Thread beim Kontextswitch noch auf RUNNING stand - er also noch gearbeitet hat. Ein Thread wechselt auf BLOCKING wenn er etwas haben will, z.B. im Netzwerk auf ein Paket wartet (egal ob TCP oder UDP). Bei einem Kontextwechsel werden alle Threads mit BLOCKING ignoriert. Hast Du also 500 Threads die im read() auf ein Paket warten, werden 500 Threads ignoriert. Du kannst auch 20 Mio Threads haben die auf etwas im Netzwerk warten. Dann stehen 20 Mio Thread auf BLOCKING und 20 Mio Threads werden ignoriert. Allerdings kommt hier ein riesieger Speicherverbrauch zustande. Die Threadinformationen müssen ja irgendwo zwischen gespeichert werden.

Kommt ein Paket an der Netzwerkkarte an, wird der entsprechender Interrupt ausgelöst. Über den Interrupt wird (durch den Socket) festgestellt für wen das Paket ist. Dann setzt der Interrupt den entsprechenden Thread (der über den Socket im read() steckt) von BLOCKING auf WAITING. Damit der Threads beim Nächsten Kontextwechsel abgearbeitet wird - er steht ja nicht mehr auf BLOCKING. Nun wird das read() „ausgeführt“ (eigentlich ist der Kram schon lange im RAM und die Netzwerkkarte empfäng evt. gerade ein andere Paket).

Auf Benutzereingaben in der Console warten → BLOCKING
Auf Daten von der Festplatte warten → BLOCKING
Auf das PaintEvent in EDT „warten“ → BLOCKING
es stehen fast alle Threads auf BLOCKING

hand, mogel

Jepp, darum nimmt der gute alte Leerlaufprozess meistens 99% CPU Zeit in Anspruch :stuck_out_tongue:

Dir ist schon bewusst das der Leerlaufprozess (oder „System Idle process“) kein Prozess ist?


void systemIdleProcess() {
    while(true);
}

wenn man 500 unabhängige Clients hat die maximal alle paar sec kurz aktiv werden,
dann sind 500 Threads, die jeweils mindestens 95+% der Zeit schlafen schon eher denkbar
als bei einer Echtzeitinteraktion, wo von jeden ständig neuer Input kommt,
so habe ich es angedeutet verstanden, was genau vorliegt ist unklar

ein Thread der alle 500 Sockets durchgeht ist jedenfalls eine verlockende Variante, falls es funktioniert,
mehr als ein Thread kann evtl. sowieso nicht arbeiten, spart das ständige Umschalten

Seien wir doch mal realistisch: Wenn 500 Clients in Echtzeit Daten übertragen, dann ist das Bottleneck definitiv nicht das Threadhandling, sondern die limitierte Übertragungsgeschwindigkeit des PCs oder Routers. Da, so wie ich den TO verstanden habe, das Programm wohl niemals auf einem richtigen Server mit Standleitung laufen wird, braucht man sich doch über das “Was wäre wenn …” Problem gar keine Gedanken machen.
Für eine realistische Anzahl an Clients sollte imho das Prinzip ein Thread pro Client keine Probleme machen, im Allgemeinen würde ich da bei dem Grundsatz bleiben: Optimieriert wird erst wenn man Probleme mit der Performance hat.
Aber um mal auf das eigentliche Problem zurückzukommen: Daran kann es doch gar nicht liegen, denn selbst wenn das ready() eine Endlosschleife bilden würde und damit 100% Rechenpower benötigen würde, irgendwann kommt auch mal wieder der Sendethread dran, das kann also höchstens die Ursache für Lags, aber nicht für einen Totalabbruch sein.
Ich hab das Programm bei mir auch mal getestet und konnte das Problem auch nicht reproduzieren. Den orginalen Problemfall kann ich leider nicht nachstellen weil mein Router (ein Speedport) alle Verbindungen blockt die von innerhalb des Netzwerks kommen (Ich hätte ja vorgeschlagen das es daran liegen könnte, aber dann dürfte gar nichts ankommen). Afaik kann man mit Wireshark auch den Networktraffic anderer PCs überwachen, u. U. lässt sich durch das überwachen des Routers mehr herausfinden.
Hast du schon mal ausprobiert, ob das Problem auch auftritt, wenn der Client auf einem anderern Rechner im selben Netzwerk läuft? Dann wäre das Problem nämlich auf deinem Rechner zu suchen (oder im Programm), ansonsten kann man die Schuld ganz klar dem Router zuweisen.

[QUOTE=mogel]Dir ist schon bewusst das der Leerlaufprozess (oder “System Idle process”) kein Prozess ist?


void systemIdleProcess() {
    while(true);
}

[/QUOTE]
Hää? Alles was ich damit sagen wollte ist, dass sogar der Leerlaufprozess erfunden wurde damit der Scheduler eben dauernd einen Thread zum umschalten hat, selbst wenn alle normalen Threads blockiert sind. Aber lassen wir das, das wird langam OT.

Wenn du von 500 Clients in Echtzeit ständig input bekommst wirst du an einen Punkt kommen, wo ein Server die Sachen nicht mehr handlen kann. Da muss man dann eben eine geeignete Architektur wählen. Muss ja nicht gleich eine Cloud sein, einfach ein 2. Server und jeder übernimmt 250 Clients.

Zum eigentlichen Problem, wurde ja schon gesagt dass es besser ist das mit einem Programm auszutesten von dem man weis dass es wirklich funktioniert.