2012-05-27 40 views
7

Así que básicamente estoy escribiendo un juego de varios jugadores cliente-servidor. Tengo un SeverCommunicationThread que crea un juego Thread si recibe un RequestForGame crea un juego Thread. Cuando envío una excepción RequestForGame lanzada java.io.StreamCorruptedException: código de tipo no válido: 00 Supongo que es porque ambos subprocesos intentan leer el mismo ObjectInputStream, no entiendo muy bien cómo funciona, solo sé cómo para usarlo ¿Podrías ayudarme a entender cuál es el problema y cómo solucionarlo? Gracias :)java.io.StreamCorruptedException: código de tipo no válido: 00

public class ServerCommunicationThread extends Thread{ 
private Socket connectionSocket; 
private ObjectInputStream inFromClient; 
private ObjectOutputStream outToClient; 
private String nickname; 
private ServerModelManager model; 


public ServerCommunicationThread(Socket connectionSocket, 
     ServerModelManager model) throws IOException { 
    this.connectionSocket = connectionSocket; 
    inFromClient = new ObjectInputStream(connectionSocket.getInputStream()); 
    outToClient = new ObjectOutputStream(connectionSocket.getOutputStream()); 
    this.model = model; 
    start(); 

} 

public void run() { 
    try { 
     String nickname = (String) inFromClient.readObject(); 
     if (model.exists(nickname)){ 
      System.out.println(nickname + " already exists"); 
      outToClient.writeObject(new MessageForClient("Please choose another nickname")); 
     } 
     else 
     { 
      System.out.println(nickname + " connected, adding to list"); 
      model.addClient(nickname, connectionSocket,outToClient,inFromClient); 
      this.nickname=nickname; 
     } 
     while(true){ 
      Object o= inFromClient.readObject();//StreamCorruptedexception 
      if(o instanceof RequestForGame) 
      { 
       RequestForGame r=(RequestForGame)o; 
       String userToPlayWith=r.getUserToPlayWith(); 
       if(userToPlayWith.equals(nickname)) 
       { 
        String message="Playing with yourself makes your palms hairy, choose another opponent"; 
        outToClient.writeObject(message); 
       } 
       else 
       { 
       System.out.println("received request to play with "+userToPlayWith+". starting game"); 
       ClientRepresentative client1=model.getClient(nickname); 
       ClientRepresentative client2=model.getClient(userToPlayWith); 
       ServerGameThread s=new ServerGameThread(client2,client1,client2.getInStream(),client1.getInStream(),client1.getOutStream(),client2.getOutStream()); 
       } 
      } 
      else if(o instanceof String) 
      { 
       String s=(String) o; 
       if(s.equals("i want to quit")) 
       { 
        model.deleteClient(nickname); 
        inFromClient.close(); 
        String q="quit"; 
        outToClient.writeObject(q); 
        connectionSocket.close(); 
        System.out.println(nickname+"has quit without exc"); 
       } 
      } 
     } 
    } catch (EOFException e) { 
     System.out.println(nickname+" has quit"); 
    } 
    catch (SocketException e) 
    { 
     System.out.println(nickname+" has quit"); 
    } 

    catch (Exception e) { 

     e.printStackTrace(); 
    } 
} 

} 
public class ServerGameThread extends Thread { 

private ClientRepresentative client1,client2; 
private ObjectInputStream inFromClient1,inFromClient2; 
private ObjectOutputStream outToClient1,outToClient2; 
private Field gameField; 
public ServerGameThread(ClientRepresentative client1, ClientRepresentative client2,ObjectInputStream inFromClient1,ObjectInputStream inFromClient2,ObjectOutputStream outToClient1,ObjectOutputStream outToClient2) 
{ 
    System.out.println("startin game thred"); 
    this.client1=client1;//client 1 goes first 
    this.client2=client2;//client 2 started game 


     this.inFromClient1=inFromClient1; 
     this.inFromClient2=inFromClient2; 
     this.outToClient1=outToClient1; 
     this.outToClient2=outToClient2; 


     gameField=new Field(); 
     System.out.println("check"); 
     start(); 
} 
public void run() 
{ 
    System.out.println("Starting game. players: "+client1.getNickname()+";"+client2.getNickname()); 
    try { 
     outToClient1.writeObject(gameField); 
     outToClient2.writeObject(gameField); 
     while(true) 
     { 
      try { 
       System.out.println("listening to "+client1.getNickname()); 
       Object o1=inFromClient1.readObject();//read move from client 1.**//StreamCorruptedexception** 

       while(!(o1 instanceof PlayerMove)) 
       { 
        o1=inFromClient1.readObject();//read move from client 1. 
       } 
       PlayerMove move1=(PlayerMove)o1; 
       System.out.println("received move "+move1+" sending to "+client2.getNickname()); 
       outToClient2.writeObject(move1); 
       System.out.println("listening to "+client2.getNickname()); 
       Object o2=inFromClient2.readObject();//read move from client 1. 
       while(!(o2 instanceof PlayerMove)) 
       { 
        o2=inFromClient2.readObject();//read move from client 1. 
       } 
       PlayerMove move2=(PlayerMove)o2; 
       System.out.println("received move "+move2+" sending to "+client1.getNickname()); 
       outToClient1.writeObject(move2); 
      } 
       catch (ClassNotFoundException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

} 
}  

el método model.addClient aunque yo no creo que el problema está aquí

public void addClient(String nickname, Socket  clientSocket,ObjectOutputStream stream,ObjectInputStream inStream) 
{ 
    clients.addClient(nickname, clientSocket,stream,inStream);//add to arraylist 
//send client list to all clients 
    String[] users=this.getAvailableClients(); 
    ObjectOutputStream[] streams=clients.getOutStreams(); 
    for(int i=0;i<streams.length;i++) 
    { 
     try { 
      streams[i].writeObject(users); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

El proxy del lado del cliente que envía a los objetos del servidor, los métodos son provocados por las acciones del usuario en la interfaz gráfica de usuario

public class Proxy { 
final int PORT = 1337; 
String host; 
String nickname; 
private Socket clientSocket; 
private ObjectOutputStream outToServer; 
private ObjectInputStream inFromServer; 
private ClientModelManager manager; 
public Proxy(String nickname,String host,ClientModelManager manager) 
{ 
    this.nickname=nickname; 
    this.host=host; 
    this.manager=manager; 
    this.connect(nickname); 
} 
public void connect(String nick) 
{ 
    Socket clientSocket; 
    try { 
     clientSocket = new Socket(host, PORT); 
     System.out.println("client socket created"); 
     outToServer = new ObjectOutputStream(clientSocket.getOutputStream()); 
     inFromServer=new ObjectInputStream(clientSocket.getInputStream()); 
     outToServer.flush(); 
     outToServer.writeObject(nick); 
     ClientReceiverThread t=new ClientReceiverThread(inFromServer,manager); 
     t.start(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
public void makeRequest(String user) 
{ 
    try 
    { 
    outToServer.writeObject(new RequestForGame(user)); 
    } 
    catch(IOException e) 
    { 
     e.printStackTrace(); 
    } 
} 
public void quit() 
{ 
    try { 
     outToServer.writeObject(new String("i want to quit")); 
     //clientSocket.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 
public void sendMove(PlayerMove move) 
{ 
    try { 
     outToServer.writeObject(move); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 

}

+0

¿Qué está haciendo ServerModelManager cuando llama a 'model.addClient (apodo, connectionSocket, outToClient, inFromClient);'? Puede haber un código dentro que corrompe la secuencia. – Vulcan

+0

addClient (agrega el usuario a una ArrayList del tipo ClientRepresantative que contiene el socket, objectouput y flujo de entrada). No lee nada – user1420273

+0

Muy bien. Además, debe enjuagar ObjectOutputStreams después de construirlos para garantizar que se envía el encabezado. Esa puede ser la razón por la que recibes ese error; el encabezado de la secuencia aún no se ha procesado. Vacíe ObjectOutputStream en el cliente y el servidor después de la creación. – Vulcan

Respuesta

6

Este problema puede ocurrir si construyes un nuevo ObjectInputStream o ObjectOutputStream sobre el mismo socket en lugar de usar los mismos para la vida del socket; si usa otro tipo de flujo sobre el mismo socket también; o si usa las secuencias de objetos para leer o escribir algo que no es un objeto y se sale de sincronización.

+1

Creo el ObjectOutputStream primero en ambos lados (Proxy, ServerCommunicationThread). Lo construyo solo una vez y luego le envío una referencia al otro Tema. No uso ningún otro tipo de transmisión. Lo único que me viene a la mente es que estoy tratando de leer un objeto del mismo ObjectInputStream en 2 hilos al mismo tiempo. (ServerCommunicationThread, ServerGameThread) ¿Puede ser este el problema? (desde la ubicación de la excepción, supongo que sí ...) – user1420273

+0

@ user1420273 Ciertamente puede, a menos que tenga la sincronización adecuada. – EJP

3

Esto también puede suceder si la JVM que lee el objeto serializado no tiene los archivos de clase/jar correctos para el objeto. Esto generalmente da como resultado un ClassNotFoundException, pero si tiene diferentes versiones de jar/clase y el serialVersionUID no se cambió entre las versiones, se produce un StreamCorruptedException. (Esta excepción también puede ser posible si hay un conflicto de nombre de clase, por ejemplo, un jar que contenga una clase diferente con el mismo nombre de clase completo, aunque probablemente también necesiten el mismo serilVersionUID).

Compruebe que el lado del cliente tenga las versiones correctas de los archivos jar y class.

+0

No, no puede. Esa condición causa una ClassNotFoundException. – EJP

+1

Hice esta respuesta, ya que solucioné correctamente el error en la pregunta instalando los archivos jar correctos. Creo que en mi caso tenía las versiones incorrectas (y la versión UID no se mantuvo correctamente), aunque hace un tiempo ... ¿También podría ser posible con conflictos de nombre de clase? @ejp Voy a enmendar mi respuesta para indicar las versiones de archivos jar. ¡Fallé para eliminar tu voto negativo, no motiva a uno a proporcionar a otros el beneficio de las experiencias! – drevicko

+0

Si tiene una discrepancia entre 'serialVersionUID', recibe una excepción que dice explícitamente, enumerando los' serialVersionUIDs.' esperados y los reales. No obtiene una 'StreamCorruptedException' que dice' 'inesperado tipo de código 0x00''. Mis-diagnosis aren beneficioso para cualquier persona – EJP

2

Si ObjectInputStream se construye una sola vez y luego sólo pasa una referencia de la misma al otro hilo luego simplemente encerrar el acceso de este objeto en el interior synchronized bloque para asegurarse de que sólo un hilo puede acceder a este objeto a la vez.

Siempre que esté leyendo ObjectInputStream solo acceda al bloque synchronized si se comparte entre varios hilos.


Código de ejemplo: (hacerlo por todas las ocurrencias de readObject())

... 
String nickname = null; 
synchronized (inFromClient) { 
    nickname = (String) inFromClient.readObject(); 
} 
3

hay otra posibilidad que me encontré en la que si se implementa una rutina de deserialización personalizado para una clase mediante la adición de este método:

private void readObject(ObjectInputStream objectInputStream) throws IOException 

continuación objectInputStream.defaultReadObject() debe ser llamado y llama antes de cualquier lee adicional de la secuencia de entrada para inicializar correctamente la junta bject.

Olvidé esto y, a pesar de que el objeto regresaba sin una excepción, fue la siguiente lectura de la secuencia de objetos que generó la excepción de código de tipo no válido.

Este enlace proporciona más información sobre el proceso: http://osdir.com/ml/java.sun.jini/2003-10/msg00204.html.

+0

Esta no es una declaración correcta del problema. El problema es que debes llamar a 'defaultReadObject().' Una vez que hayas hecho eso, no es importante que leas la cantidad exacta de bytes de tus cosas. – EJP

+0

Correcciones agregadas. – user2219808

2

Yo también tuve esta excepción. Ocurrió porque utilicé dos subprocesos para la clase Servidor y la clase Cliente. Usé un hilo para enviar y recibir objetos. Entonces estuvo bien. Esta es una manera fácil de resolver el problema si no está familiarizado con synchronized.

1

java.io.StreamCorruptedException: Código de tipo no válido: 00

Hace poco se encontró con este problema, no hacer lo que hizo OP sin embargo. Realicé una búsqueda rápida en Google y no encontré nada que fuera demasiado útil y porque creo que lo resolví. Estoy haciendo un comentario con mi solución.

TLDR: No tiene varios hilos que escriban al mismo flujo de salida al mismo tiempo (en su lugar se turnan). Causará problemas cuando el lado del cliente intente leer los datos. La solución es bloquear la escritura en la salida.

Estoy haciendo algo muy similar a OP, haciendo un juego multijugador (modelo cliente-servidor). Tengo un hilo como OP que está escuchando el tráfico. Lo que estaba sucediendo, en mi lado del servidor era que el servidor tenía varios hilos que estaban escribiendo en la transmisión de un cliente al mismo tiempo (no creía que fuera posible, el juego era base de media vuelta). El hilo del lado del cliente que estaba leyendo el tráfico entrante lanzaba esta excepción. Para resolver esto básicamente puse un candado en la parte que escribió en la secuencia del cliente (en el lado del servidor) para que cada subproceso en el lado del servidor tuviera que obtener el bloqueo antes de escribir en la secuencia.

Cuestiones relacionadas