Socket Problem mit ObjectInput/OutputSream

chaostheory

Bekanntes Mitglied
Hallo,
ich versuche gerade ein 2D-Spiel von mir netzwerkfähig zu machen. Ich versende verschiedene Klassen über einen ObjecOutputStream, für Sounds, Statusänderungen, Positionen usw.
Mit Abstand am öftesten versendet wird ein Array aus SpriteMessage, die lediglich drei Integer-Werte speichert.
Allerdings bekomme ich früher oder später jedes Mal eine ArrayStore- oder StreamCorruptedException. Mal läuft es nur einige Sekunden, mal eine Minute.
Code:
Exception in thread "Thread-8" java.lang.ArrayStoreException
Die StreamCorruptedExceptions haben verschiedene Fehlercodes, z.b. 00 oder 6C.
Alle Exceptions treten beim Lesen auf:
[JAVA=37]message = inputStream.readObject();[/code]

Sehr merkwürdig: Schreibe ich für jedes empfangene Objekt eine Nachricht in System.out (s. Senden Z. 37) funktioniert alles, läuft nur langsamer...

Verbindung herstellen:
[JAVA=83]//Stellt eine Verbindung zum angegebenen Socket her und gibt den Erfolg zurück
public boolean connect(Socket socket, boolean toHost) {
this.socket = socket;
try {
outputStream = new ObjectOutputStream(socket.getOutputStream());
inputStream = new ObjectInputStream(socket.getInputStream());
gameListener = new GameListener(main, inputStream);
gameListener.start();
if(toHost) main.setProgrammeStatus(ProgrammeStatus.NETWORK_CLIENT);
else {
main.setProgrammeStatus(ProgrammeStatus.NETWORK_HOST);
sendDisplayMode();
}
main.setStatus(GameStatus.MULTIPLAYER_GAME);
} catch (IOException e) {e.printStackTrace(); return false;}
return true;
}[/code]

Senden:
[JAVA=35]public void sendObject(Object object) {
//Löscht man die print-Befehle klappt gar nichts mehr. Warum weiß niemand.
//main.print("Sende " + object);
if(isConnected()) {
try {
outputStream.writeObject(object);
//main.print("Übertragung erfolgreich.");
} catch(SocketException e) {
if(e.getLocalizedMessage().equals("Connection reset")) {
main.getCommunicationManager().closeConnection();
main.getComponentHandler().showPopUp("Verbindung unterbrochen!");
}else e.printStackTrace();
}
catch (IOException e) {e.printStackTrace();}
}
}[/code]

Empfangene Nachrichten auswerten:
[JAVA=29]@Override
public void listen() {
Object message = null;
try {
message = inputStream.readObject();
} catch(SocketException e) {
if(e.getLocalizedMessage().equals("Connection reset") || e.getLocalizedMessage().equals("socket closed")) {
main.getCommunicationManager().closeConnection();
main.getComponentHandler().showPopUp("Verbindung unterbrochen!");
}else e.printStackTrace();
}
catch (IOException e) {e.printStackTrace();}
catch (ClassNotFoundException e) {e.printStackTrace();}

if(message != null) {
//main.print("Objekt erhalten: " + message);
if(message instanceof SpriteMessage[]) {
SpriteMessage[] sprites = (SpriteMessage[]) message;
for(SpriteMessage spriteMessage : sprites) {
if(displayFactorWidth != 1) spriteMessage.setX(Math.round(Math.round(spriteMessage.getX() * displayFactorWidth)));
if(displayFactorHeight != 1) spriteMessage.setY(Math.round(Math.round(spriteMessage.getY() * displayFactorHeight)));
}
main.getDrawManager().setSpriteMessages(sprites);
}else
if(message instanceof InputMessage) {
switch((InputMessage) message) {
case PLAYER_MOVE_CENTER: main.getGameManager().setPlayerDirection(1, Direction.CENTER); break;
case PLAYER_MOVE_RIGHT: main.getGameManager().setPlayerDirection(1, Direction.RIGHT); break;
case PLAYER_MOVE_LEFT: main.getGameManager().setPlayerDirection(1, Direction.LEFT); break;
case PLAYER_SHOOT: main.getGameManager().shootArrow(1); break;
}
}else
if(message instanceof StatusMessage) {
switch((StatusMessage) message) {
case LEVELCHANGE_START: main.setStatus(GameStatus.MULTIPLAYER_LEVELCHANGE);
main.getGameManager().setLevel(main.getGameManager().getLevel() + 1); break;
case LEVELCHANGE_END: main.setStatus(GameStatus.MULTIPLAYER_GAME); break;
case GAME_OVER: main.setStatus(GameStatus.SCORE); break;
case GAME_RESTART: main.setStatus(GameStatus.MULTIPLAYER_GAME); break;
case CONNECTION_END: main.getCommunicationManager().closeConnection();
main.print("Partner hat Spiel verlassen, schließe Verbindung.");
main.getComponentHandler().showPopUp("Der Partner hat das Spiel verlassen."); break;
}
}else
if(message instanceof SoundNumber) {
main.getSoundHandler().playSound((SoundNumber) message);
}else
if(message instanceof PlayerScoreMessage) {
main.getGameManager().setPlayerPoints(0, ((PlayerScoreMessage) message).getFirstScore());
main.getGameManager().setPlayerPoints(1, ((PlayerScoreMessage) message).getSecondScore());
}else
if(message instanceof DisplayModeMessage) {
main.print("DisplayMode erhalten");
DisplayMode ownDisplayMode = main.getScreenHandler().getCurrentDisplayMode();
DisplayMode oppositeDisplayMode = ((DisplayModeMessage) message).getDisplayMode();
main.print(ownDisplayMode.getWidth() + " " + ownDisplayMode.getHeight());
main.print(oppositeDisplayMode.getWidth() + " " + oppositeDisplayMode.getHeight());
displayFactorWidth = (double) 1 / oppositeDisplayMode.getWidth() * ownDisplayMode.getWidth();
displayFactorHeight = (double) 1 / oppositeDisplayMode.getHeight() * ownDisplayMode.getHeight();
main.print("DisplayFactorWidth: " + displayFactorWidth);
main.print("DisplayFactorHeight: " + displayFactorHeight);
}
}
}[/code]

SpriteMessage:
[JAVA=5]public class SpriteMessage implements Serializable {

private static final long serialVersionUID = -7914187131101524916L;

private final int imageNumber;
private int x;
private int y;

public SpriteMessage(int imageNumber, double x, double y) {
this.imageNumber = imageNumber;
this.x = Math.round(Math.round(x));
this.y = Math.round(Math.round(y));
}

public int getImageNumber() {
return imageNumber;
}

public int getX() {
return x;
}

public int getY() {
return y;
}

public void setX(int x) {
this.x = x;
}

public void setY(int y) {
this.y = y;
}
}[/code]
 
warum schreibst du dir eine "daten-klasse" und haust davon noch ein paar in ein array / ne list ... wenn es eh nur "raw-daten" sind die du auch in string-form über die streams des sockets schicken kannst ...

ich denke das "serialisierung" hier ein wenig overkill ist
 
Naja, ich würde das eher per DataInput und DataOuputStream lösen und mir ein eigenes Protokoll überlegen. In deinem Fall könnte zu erst die Anzahl der SpriteMessages die gesendet werden sollen als int geschrieben werden und danach von jeder einzelnen SpriteMessage die 3 relevanten ints geschrieben werden.
 
Zunächst hatte ich auch die Lösung, aber als ich immer mehr unterschiedliche Datentypen hatte habe ich den ObjectInputStream genutzt, der frisst ja alles.
Das wird aber wohl die bessere Lösung sein, ich versuche das mal.
 
Wie meinst du das, Strings verschicken? Du meinst ich versende String-Arrays und die Strings sehen dann in etwa so aus: x;y;number ?

so in etwa ... weil eine klasse schreiben ... nur um darin 3 ints zu halten ... das ist absoluter overkill ...
dafür kannst du dann auch wirklich DataInput/OutputStream verwenden und die ints direkt schreiben ... spart auf jeden fall CPU last und traffic
 
Da das alles über TCP läuft muss ich mir dann auch keinerlei Sorgen über falsche Reihenfolge oder Pakete machen, richtig? Ich muss also keine Fehler abfangen (Abgesehen von Exceptions natürlich), oder?
 
kennst du google und wikipedia ? dann nutze bitte diese um dir deine zuletzt gestellten fragen selbst zu beantworten ... denn die antwort darauf findet man in den jeweiligen spezifikationen
 

Zurück
Oben