# Versenden von Objekten braucht zu lange



## xorm (6. Feb 2010)

Hallo, ich habe ein kleines Problem bei der Programmierung eines kleinen Netzwerkspiels.

Folgende Situation:
Es gibt einen Server mit dem sich mehrere Clients verbinden können. Der Server aktualisiert im 20ms Abstand den Spielstatus und sendet den aktuellen Status an alle Clients. Zum senden wird ein ObjectOutputStream verwendet. Das gesendete Status-Objekt ist nicht besonders groß, es enthält nur einige Koordinaten.

Solang sich nur ein Client mit dem Server verbunden hat, läuft alles rund. Wenn sich allerdings ein zweiter Client mit dem Server verbindet, kommt es im Abstand von ungefähr 2s vor, dass das Senden des Status-Objektes relativ lange dauert.

Genauer gesagt: Der Aufruf von

```
objectStream.writeObject(state);
objectStream.flush();
```
braucht 0,5s bis >1s.

Allerdings dauert das Senden nur bei einem der beiden Clients so lange (unterschiedlich bei welchem). Das Senden des selben Status-Objektes an den jeweils anderen Client verläuft ohne Probleme, weshalb es wohl nicht an dem gesendetem Objekt liegen kann. Zudem tritt das Problem auch auf wenn immer das gleiche Objekt an die Clients gesendet wird.

Hat vielleicht jemand eine Idee an was das liegen könnte?


----------



## dayaftereh (6. Feb 2010)

Hey,
Ich glaube der ObjectOutputStream hat eine Chash, also er speicher sich die letzten gesendeten Objekte! Versuch mal reset() auf zu rufen oder verschicke mal das Object mit writeUnshared(Object obj) . Baue die mal ein Ping Packet, also das du von Client zum Server und der Server dan sofort wider zum Client schickt, und in dem Packet ist eine long mit der System Zeit vom Client. Gitb dan mal aus wie lange es gedauert hat!

Der Socket Bufferd die Bytes glaube ich, versuche mal bei dem Socket "setTcpNoDelay() " == true zu setzten! bei mir hat das Performance gebracht!

Ich würde über ein DataOutputStream und DataInputStream nach denken! ObjectOutputStream haben eine Großen Overhead!
*Edit:*
Tips zu DataOutputStream / DataInputStream 

Ich würde jedem Objekt eine int oder short als ID geben, und dan Jedem Packet eine Byte

Also zum Beispiel für das Packet ValidateObjekt 

Aufbau des Packetes ValidateObjekt: 
Packet ID = Byte (länge 1 byte) ==> Packet Typ also welches Packet ankommt
Objekt ID = Short ( Länge 2 bytes) ==> Um welches Objekt es geht
x Position = int (länge 4 bytes) ==> Die neue X Position
y Position = int (länge 4 bytes) ==> Die neue Y Position
z Position = int (länge 4 bytes) ==> Die neue Z Position

Auf der anderen seite ,liest du dan immer eine Byte, jetzt kommt der Wert vom ValidateObjekt , dan weißt du das dan eine Short und 3 int's kommen,und dann das negste Packet! mach dir eine großen switch Case wo du die Bytes Prüfst! so hast du kein Großen OverHead!

Hier mal ein Kurzes Beispiel:

```
public static final int VALIDATET_OBJEKT = 1;

	private boolean started = true;

	private Socket socket = null;

	public void run() {

		DataInputStream in = new DataInputStream(socket.getInputStream());

		while (started) {

			int typ = in.read();

			switch (typ) {
			case VALIDATET_OBJEKT:
				// Das Ambesten in eine Klasse ValidatetObjekt auslagern und die
				// Interface recive und send einbauen
				short objektID = in.readShort();
				int x = in.readInt();
				int y = in.readInt();
				int z = in.readInt();
				break;

			}

		}

	}
	
	/**
	 * Ein Beispiel für eine Methode zum Senden von einem ValidatetObjekt
	 * @param out
	 */
	public void send(DataOutputStream out){
		out.write(VALIDATET_OBJEKT);
		out.writeShort(objektID);
		out.writeInt(x);
		out.writeInt(y);
		out.writeInt(z);
	}
```

Warum DataOutputStream/ DataInputStream?

Weil du direcht bytes , short's ,int's , long's,doubels's lesen und schrieben Kannst, musst sie nicht noch erst in eine byte Array machen!

Hoffe ich Konnte Helfen! wen nicht dan PM


----------



## xorm (6. Feb 2010)

Danke für den Beitrag.

Ja ObjectStreams puffern die Daten selbstständig. Im Moment resete ich allerdings vor jedem senden von Daten den Stream, weshalb es daran nicht liegen dürte. Das NoDelay Flag des Sockets ist ebenfalls schon gesetzt. Sorry, die 2 Dinge hätte ich wohl noch in den Startbeitrag schreiben sollen.
Und nochwas: Das Problem tritt nur auf, wenn die Daten tatsächlich über das Netzwerk gehen. Wenn ich Server und Client lokal starte, läuft alles korrekt.

Ich benutze ObjectStreams weil sie angenehmer zu benutzen sind. Ich schicke einfach mein Zustands-Objekt von dem Server an den Client und kann im Client dann direkt damit weiter arbeiten. Mit DataStreams müsste ich erst alle Werte einzeln lesen und mir das entsprechende Objekt dann wieder zusammen bauen.

Wenn ich in absehbarer Zeit die Ursache nicht finde, werde ich es aber wahrscheinlich mal mit DataStreams versuchen.


----------



## Empire Phoenix (7. Feb 2010)

Angenehmheit erkauft man sich immer zu einem Preis, abgesehen davon sind Object streams extrem ineffizient, 
Obengenanntes beispiel, ist ca. 200byte aufwärts, während das selbe direkt keine 20 sind. Einen Unterschied von Faktor 10 sollte man nicht missachten, weil es einfacher war.


----------



## dayaftereh (7. Feb 2010)

Ich muss mich Empire Phoenix anschließen! Du machst ein Realtime game? wenn ja würde ich sofort vom ObjectStreams weg! der Overhead ist viel zu große!


----------



## tuxedo (8. Feb 2010)

dayaftereh hat gesagt.:


> Ich muss mich Empire Phoenix anschließen! Du machst ein Realtime game? wenn ja würde ich sofort vom ObjectStreams weg! der Overhead ist viel zu große!



Naja, man kann mit Object*Streams vernünftig umgehen oder auch nicht. Der Zeit und Datenoverhead hält sich absolut in Grenzen wenn man sich auf DTOs mit einfachen primitiven beschränkt. Mit nem 0815 DSL Anschluss der unteren Leistungsklasse gibts da gar keine Probleme.
Wenn man halt Object*Streams voll ausnutzt, dann kommt schon ein wenig Overhead zusammen...

- Alex


----------

