![]() |
| | Themen-Optionen | Thema durchsuchen |
| | Nach oben #1 |
| Sesselkleber Registriert seit: 17.01.2005
Beiträge: 576
|
Hallo Forum, ich hoffe ihr könnt mir auf die Sprünge helfen. Ich hab das ganze mal unter Netzwerkprogrammierung gepackt, ich denke es passt hier ganz gut rein. Das ganze wird ein Testcode für ein Spiel. Also folgendes Szenario: Ich habe ein Serverprogramm und ein Clientprogramm. Der Server lauscht auf einen Port, Client verbindet sich darauf. Anfangs gibt es mehrere kleine Verbindungen. Alle über TCP/IP. Die Verbindung wird jeweils dadurch beendet, dass der Server eine Anfrage beantwortet und anschließend den Socket schließt. Jetzt kommt aber der Hauptteil des Programms, und damit habe ich ein wenig Probleme. Die Verbindung soll nun dauerhaft offen bleiben und die Clients sollen die neuen Informationen der jeweils anderen Clients erhalten. Wenn der Spieler auf Client1 sich bewegt sollen alle anderen Clients die Information darüber erhalten. Das ganze muss möglichst Zeitnah erfolgen. Meine Idee war folgende: Jeder Spieler hat auf dem Server einen eigenen Thread. Das ist nötig da jegliche Verbindung jederzeit Daten empfangen und senden kann. Die Threads werden von einer Klasse (Handler) verwaltet. Bewegt sich einer der Spieler sendet er seine neuen Koordinaten an den Server. Der Server erkennt anhand des eingehenden Strings was er tun soll (update der Spielerposition), durchsucht alle Spieler und trägt in einen Buffer (ein Vector) eine Zeichenfolge (UpdateSpielerPosition,Spielername,neuX,neuY). In Regelmäßigen Abständen (sehr oft) fragt der Client bei dem Server an ob neue Daten für ihn vorliegen. Der Server antwortet mit dem Inhalt des Vector-Buffers der für den Spieler gefüllr wurde. Der Client weiß was die Einträge bedeuten und wendet sie auf die Spieler an. Das funktioniert wunderbar. Um zeitnah zu sein muss der Client aber bei wirklich jeder kleinen Bewegung des Spielers die neue Position an den Server senden. Ebenfalls muss der Client sehr oft nach Updates fragen. Zwar wird die Verbindung zwischen Client und Server zwischenzeitlich nicht abgebaut (also die Sockets bleiben dauerhaft offen, es wird lediglich ein Byte gesendet, dass den Ende eines "Befehls" angbit), trotzdem sind das eine Menge Daten die ausgetauscht werden müssen. Außerdem habe ich ein Problem mit der Synchronisation der Threads auf dem Server. Theoretisch könnte ich auch dauerhaft alle den Client betreffenden Updates einfach an den Client senden anstatt den Client anfragen zu lassen, allerdings könnte das zu Schwierigkeiten kommen wenn der Client nicht mit der Abarbeitung hinterher kommt. Daher die Anfrage. Wenn im Moment aber ein Thread bevorzugt wird, bekommt er sehr viele Daten, während andere Threads ewig auf Ihre Daten warten müssen. Das kann es meiner Meinung auch nicht sein. Daher meine Frage ob ihr andere Vorschläge habt, oder ob ihr Ideen für das funktionierende syncen der Threads habt. Gruß Sparrow |
| | |
| | Nach oben #2 | ||
| Benutzer Registriert seit: 15.11.2005
Beiträge: 75
| Zitat:
Zitat:
Das Prinzip könnte so aussehen: Server: Code: import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Server {
class Handler implements Runnable {
protected BufferedReader Rdr;
protected OutputStream Out;
protected int Val;
protected String CliID;
public Handler( Socket cs) throws IOException {
//--- create a Reader that can be used to read data from the client
Rdr = new BufferedReader( new InputStreamReader( cs.getInputStream()));
//--- create an OutputStream that can be used to send data to the client
Out = cs.getOutputStream();
//--- spawn a thread for client-input-handling
new Thread( this).start();
//--- register ourselves in Server's list
Handlers.add( this);
}
public void run() {
while ( true) {
try {
//--- read data from this Handler's client and pass it to all connected clients
String cmd = Rdr.readLine();
System.out.println( this + ".run(:( cmd = " + cmd);
propagate( cmd);
} catch( Exception e) {
//--- simple error-handling: just disconnect ;-)
e.printStackTrace();
Handlers.remove( this);
break;
}
}
}
public void send( String data) throws IOException {
//--- send the passed command to this Handler's client
Out.write( (data + "\r\n").getBytes());
Out.flush();
}
}
protected int Port;
protected ServerSocket Sock;
protected List<Handler> Handlers = new ArrayList<Handler>();
public Server( final int port) {
Port = port;
}
public void start() throws IOException {
//--- create a socket and listen for connections
Sock = new ServerSocket( Port);
while ( true) {
//--- acceptConnection is supposed to spawn a new thread
acceptConnection();
}
}
protected void acceptConnection() throws IOException {
//--- wait for request (this one blocks until a new client connects)
Socket cs = Sock.accept();
//--- handle in a different thread to avoid server-blocking
new Handler( cs);
}
protected void propagate( String cmd) throws IOException {
//--- send the passed command to all connected clients
Iterator<Handler> handlers = Handlers.iterator();
while ( handlers.hasNext()) {
handlers.next().send( cmd);
}
}
public static void main( String[] args) {
try {
Server srv = new Server( 8100);
srv.start();
} catch ( Exception e) {
e.printStackTrace();
}
}
}
Code: import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Client implements Runnable {
protected String ID;
protected String Host;
protected int Port;
protected Socket Sock;
protected int Val;
protected BufferedReader Rdr;
public Client( final String host, final int port) {
//--- Server's address
Host = host;
Port = port;
//--- a unique id
ID = "Cli" + System.currentTimeMillis();
//--- application data (just a dummy for real-world data)
Val = 0;
}
public void connect() throws IOException {
//--- establish a connection to our server
Sock = new Socket( Host, Port);
//--- create a Reader that can be used to read data from the server
Rdr = new BufferedReader( new InputStreamReader( Sock.getInputStream()));
//--- spawn a thread for server-message-handling
(new Thread( this)).start();
}
protected void handleInput( String cmd) {
//--- this one is not much more than a dummy: dispatch user-input and recalculate application-data
if ( "+".equals( cmd)) {
Val++;
sync();
} else if ( "-".equals( cmd)) {
Val--;
sync();
} else if ( cmd != null) {
System.out.println( "?? " + cmd + " ??");
}
}
public void run() {
while ( true) {
try {
//--- read a message from the server
String cmd = Rdr.readLine();
System.out.println( "Server-Message: " + cmd);
} catch ( Exception e) {
e.printStackTrace();
break;
}
}
}
protected void sync() {
//--- send application-data to our server
try {
Sock.getOutputStream().write( ("ID=" + ID + ",VAL="+Val + "\r\n").getBytes());
Sock.getOutputStream().flush();
} catch ( IOException iox) {
iox.printStackTrace();
}
}
public static void main( String[] args) {
try {
Client cli = new Client( "localhost", 8100);
cli.connect();
BufferedReader rd = new BufferedReader( new InputStreamReader( System.in));
System.out.println( "Connected.");
System.out.println( "Type <+>+<Enter> or <->+<Enter> to send data to the server");
while ( true) {
cli.handleInput( rd.readLine());
}
} catch ( Exception e) {
e.printStackTrace();
}
}
}
| ||
| | |
| | Nach oben #3 |
| Sesselkleber Registriert seit: 17.01.2005
Beiträge: 576
|
Ok, dann bin ich ja gar nicht so falsch mit dem Code den ich hier habe. Der sieht nämlich recht ähnlich aus. Gut, wahrscheinlich hast du Recht und wir gehen davon aus, dass der Client entsprechend schnell die Daten verarbeitet. Also lassen wir ihn nicht mehr anfragen. Eine andere Sache ist, dass der Client recht häuftig die updates vom Server erhalten muß. Nach möglichkeit 30 mal pro sekunde, das wäre nämlich die Framerate in der das Spiel läuft. Wenn ein Spieler geht, dann soll man ja sehen wie er sich bewegt. Da er ja jederzeit die Richtiung wechseln kann muß ich den anderen Clients (zumindest die auf der selben Map sind) die neuen Koodinaten mit jedem neuen Frame mitschicken. Ist das raelistisch, oder sollte man eine andere Möglichkeit finden? Gruß Sparrow |
| | |
| | Nach oben #4 |
| Benutzer Registriert seit: 15.11.2005
Beiträge: 75
|
Vermutlich muss es wohl gewäherleistet sein, dass alle Spiele die Bewegungen gleichzeitig sehen; es geht also eigentlich nicht, dass man sich auf seinem eigenen Rechner bewegt und diese Bewegung dann lediglich an den Server meldet, der diese dann an alle anderen Clients propagiert; vielmehr muss die lediglich dieAnforderung, sich zu bewegen, an den Server geschickt werden. Der Server berechnet dann die neue Position und schickt diese dann quasi gleichzeitig an alle Clients. Ob man allerdings 30 Updates pro Sekunde erreichen kann, halte ich noch für fraglich. Dazu muss der Server nicht nur einige Rechenpower besitzen, sondern auch eine gewisse Bandbreite bes. im Upstream haben (er multipliziert ja den Traffic: ein Update eines Clients führt zu einem Update an alle Clients). |
| | |
| | Nach oben #5 |
| Benutzer Registriert seit: 15.11.2005
Beiträge: 75
|
Noch eine Idee: wenn man es nicht schafft, die Updates mit der Frequenz der Framerate zu verteilen, dann könnte man dem Client etwas mehr Arbeit überlassen: die Spieler bekommen vom Server bei jedem Update nicht nur eine Position, sondern auch einen Vektor (also Richtung und Geschwindigkeit der Bewegung), mit dem sie dann beliebig viele Zwischenschritte bis zum nächsten Update interpolieren können. Das dient aber nur der flüssigeren Darstellung; insbesondere sind in der zeit zwischen zwei Updates keine Richtungsänderungen möglich. Daher kann eine eventuelle Collision-Detection trotzdem (vorab) auf dem Server erfolgen.
|
| | |
![]() |
| Lesezeichen |
| Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1) | |
| Themen-Optionen | Thema durchsuchen |
| |
Ähnliche Themen | ||||
| Thema | Autor | Forum | Antworten | Letzter Beitrag |
| Thread mehrfach starten | jack77 | Desktop-Applikationen und Grafik | 18 | 07.03.2007 17:44 |
| Anzeige, wann ein Thread erstellt wurde hinzugefügt | Ben | Archiv | 5 | 25.01.2006 22:55 |
| Problem bei der Einbindung eines Applets in HTML | exoskelett | Desktop-Applikationen und Grafik | 13 | 24.01.2006 18:45 |
| Thread in Applet wird nicht gestartet? | Ben | Desktop-Applikationen und Grafik | 2 | 26.10.2005 20:33 |
| Problem bei Thread für mp3 player | Eddi | Allgemeine Java-Programmierung | 6 | 30.01.2005 16:18 |