2012-05-27 2 views
7

Так что в основном я пишу многопользовательскую игру клиент-сервер. У меня есть SeverCommunicationThread, который создает gameThread, если он получает RequestForGame, создает gameThread. Когда я отправляю исключение RequestForGame, вызывается java.io.StreamCorruptedException: недопустимый код типа: 00 Я предполагаю, что это связано с тем, что оба потока пытаются читать один и тот же объект ObjectInputStream, я не очень понимаю, как это работает, я просто знаю, как использовать его. Не могли бы вы помочь мне понять, в чем проблема и как это исправить? Спасибо :)java.io.StreamCorruptedException: недопустимый код типа: 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(); 
    } 

} 
}  

метод model.addClient, хотя я не думаю, что проблема здесь

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(); 
     } 
    } 
} 

Клиентская прокси, который отправляет объекты на сервер, методы вызываются действиями пользователя в GUI

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

Что делает ServerModelManager, когда вы вызываете 'model.addClient (псевдоним, connectionSocket, outToClient, inFromClient);'? Внутри него может быть код, который искажает поток. – Vulcan

+0

addClient (добавляет пользователя в ArrayList типа ClientRepresantative, который поддерживает сокет, objectouput и поток ввода.) Он ничего не читает – user1420273

+0

Хорошо. Кроме того, вы должны очистить ObjectOutputStreams после их создания, чтобы гарантировать отправку заголовка. Это может быть причиной, по которой вы получаете эту ошибку; заголовок потока еще не прошел. Сбросьте ObjectOutputStream как на клиент, так и на сервер после создания. – Vulcan

ответ

6

Эта проблема может произойти, если вы создаете новый ObjectInputStream или ObjectOutputStream над одним и тем же сокетом вместо использования тех же самых для жизни сокета; если вы используете другой тип потока по одному и тому же сокету; или если вы используете потоки объектов для чтения или записи чего-либо, что не является объектом, и вы не синхронизированы.

+1

Я создаю ObjectOutputStream сначала с обеих сторон (Proxy, ServerCommunicationThread). Я создаю его только один раз, а затем просто отправлю ссылку на него в другой поток. Я не использую какой-либо другой поток. Единственное, что приходит в голову, это то, что я пытаюсь одновременно прочитать объект из одного объекта ObjectInputStream в 2 потоках. (ServerCommunicationThread, ServerGameThread) В этом проблема? (из местоположения исключения я бы так предположил ..) – user1420273

+0

@ user1420273 Конечно, это возможно, если у вас нет соответствующей синхронизации. – EJP

3

Это также может произойти, если JVM, читающий сериализованный объект, не имеет правильных файлов класса/jar для объекта. Обычно это приводит к ClassNotFoundException, но если у вас разные версии jar/class и serialVersionUID не был изменен между версиями, производится StreamCorruptedException. (Это исключение также может быть возможным, если существует конфликт имен классов. Например: банку, содержащую другой класс с тем же полным именем класса, хотя они, вероятно, также нуждаются в том же serilVersionUID).

Убедитесь, что на стороне клиента установлены правильные версии банок и файлов классов.

+0

Нет, не может. Это условие вызывает исключение ClassNotFoundException. – EJP

+1

Я принял этот ответ, поскольку я успешно исправил ошибку в вопросе, установив правильные файлы jar. Я верю, что в моем случае у меня были неправильные версии (и UID версии не поддерживался должным образом), хотя это было давно. Это также возможно с конфликтами имен классов? @ejp. Я исправлю свой ответ, чтобы указать версии файлов jar, - освободился, чтобы удалить ваше голосование, но не мотивирует его предоставлять другим возможность использовать один опыт! – drevicko

+0

Если у вас есть несоответствие 'serialVersionUID', вы получаете исключение, которое явно говорит об этом, перечисляя как ожидаемые, так и фактические' serialVersionUIDs.' Вы не получаете 'StreamCorruptedException', в котором говорится« неожиданный код типа 0x00 ». Mis-диагнозы aren «Это выгодно никому. – EJP

2

Если ObjectInputStream сконструирован только один раз, а затем просто передал ссылку на другую тему, просто добавьте доступ к этому объекту внутри блока synchronized, чтобы убедиться, что только один поток может получить доступ к этому объекту за раз.

Всякий раз, когда вы читаете от ObjectInputStream, просто обращайтесь к нему внутри блока synchronized, если он делится между несколькими потоками.


Пример кода: (сделать это для всех вхождений readObject())

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

Там другая возможность, что я натыкался, где, если вы реализуете пользовательские десериализации процедуру для класса путем добавления этого метода:

private void readObject(ObjectInputStream objectInputStream) throws IOException 

затем objectInputStream.defaultReadObject() должен быть вызван и вызывается перед дальше считывает из входного потока, чтобы правильно инициализировать о ▪ Таблица.

Я пропустил это и, несмотря на то, что объект, возвращающийся без исключения, был брошен, это было следующее чтение потока объектов, которое смутно подняло исключение недопустимого типа кода.

Эта ссылка содержит дополнительную информацию о процессе: http://osdir.com/ml/java.sun.jini/2003-10/msg00204.html.

+0

Это неправильная постановка проблемы. Проблема в том, что вы должны вызывать 'defaultReadObject().' Как только вы это сделали, не важно, чтобы вы читали точное количество байтов ваших собственных вещей. – EJP

+0

Исправления добавлены. – user2219808

2

У меня тоже было это исключение. Это произошло потому, что я использовал два потока для класса Server и класса Client. Я использовал один поток для отправки и приема объектов. Тогда все было нормально. Это простой способ решить проблему, если вы не знакомы с synchronized.

1

java.io.StreamCorruptedException: неверный код типа: 00

Я недавно столкнулся с этой проблемой, а не делать то, что OP сделал хотя. Был быстрый поиск Google и не нашел ничего, что было слишком полезно, и потому, что я решил, что решил, я комментирую свое решение.

TLDR: не имеет нескольких потоков, которые записываются в один и тот же выходной поток одновременно (вместо этого по очереди). Возникнут проблемы, когда клиентская сторона пытается прочитать данные. Решение помещает блокировку записи для вывода.

Я делаю что-то очень похожее на OP, создавая многопользовательскую (клиент-серверную модель) игру. У меня есть поток, подобный OP, который прослушивает трафик. То, что происходило на моей стороне сервера, было то, что на сервере было несколько потоков, которые писали потоку клиента одновременно (не думаю, что это было возможно, игра была полуоборотной базой). Поток клиента, который читал входящий трафик, выбрасывал это исключение. Чтобы решить эту проблему, я в основном помещаю блокировку на часть, которая написана в потоке клиента (на стороне сервера), чтобы каждый поток на стороне сервера должен был получить блокировку перед записью в поток.

Смежные вопросы