2012-05-27 52 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

當您調用'model.addClient(nickname,connectionSocket,outToClient,inFromClient)時,ServerModelManager在做什麼?其中可能存在破壞流的代碼。 – Vulcan

+0

addClient(將用戶添加到ClientRepresantative類型的ArrayList,用於保存套接字,對象輸入和輸入流)。它不會讀取任何內容 – user1420273

+0

好的。另外,你應該在構造它們之後刷新ObjectOutputStreams,以確保發送頭文件。這可能是您收到該錯誤的原因;流頭還沒有經過。在創建後刷新客戶端和服務器上的ObjectOutputStream。 – Vulcan

回答

6

這個問題可以發生,如果你在同一個套接字上構建一個新的ObjectInputStreamObjectOutputStream,而不是在套接字的生命週期中使用相同的套接字;如果您在同一個套接字上使用另一種類型的流,或者如果您使用對象流來讀取或寫入不是對象的內容,並且不同步。

+1

我首先在兩端創建ObjectOutputStream(Proxy,ServerCommunicationThread)。我只構造一次,然後發送一個引用到另一個線程。我不使用任何其他類型的流。 唯一想到的是我試圖在同一時間從2個線程中的同一個ObjectInputStream中讀取一個對象(ServerCommunicationThread,ServerGameThread)這可能是問題嗎? (從我將假設的例外的位置如此..) – user1420273

+0

@ user1420273當然,它可以,除非你有適當的同步。 – EJP

3

如果讀取序列化對象的JVM沒有正確的對象的類/ jar文件,也會發生這種情況。這通常會導致ClassNotFoundException,但如果您有不同的jar/class版本,並且serialVersionUID在版本之間沒有更改,則會生成StreamCorruptedException。 (如果存在類名衝突,這個例外也是可能的,例如:包含具有相同完整類名的不同類的jar,儘管它們可能也需要相同的serilVersionUID)。

檢查客戶端是否有正確版本的jar和類文件。

+0

不,它不能。該情況導致ClassNotFoundException。 – EJP

+1

我做了這個答案,因爲我已經通過安裝正確的jar文件成功解決了問題中的錯誤。我相信在我的情況下,我有錯誤的版本(並且版本UID未正確維護),儘管現在是不久前的...也可能出現類名衝突? @ejp我會修改我的答案,以表明jar文件版本 - 免費刪除您的投票,它不會激勵人們提供一些經驗的好處! – drevicko

+0

如果你有一個'serialVersionUID'不匹配,你會得到一個明確的異常,列出預期的和實際的'serialVersionUIDs.'你不會得到一個'StreamCorruptedException',它表示'意外的類型代碼0x00.'錯誤診斷aren對任何人都沒有好處。 – EJP

2

如果ObjectInputStream只構造一次,然後只傳遞給其他線程的引用,那麼只需在​​塊中包含此對象的訪問權限,以確保一次只有一個線程可以訪問此對象。

如果您正在從ObjectInputStream讀取,則只需在​​塊內對其進行訪問(如果它在多個線程之間共享)。


示例代碼:(做它的readObject()所有出現)

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

還有,我加入這個方法橫跨在那裏,如果你實現了一個類的自定義序列化程序跑了另一種可能性:

private void readObject(ObjectInputStream objectInputStream) throws IOException 

然後objectInputStream.defaultReadObject()必須被調用並調用之前的任何進一步讀取輸入流正確地初始化鄰bject。

我錯過了這一點,儘管對象沒有拋出異常而返回,但它是對象流的下一次讀取,它會混淆地引發無效的類型代碼異常。

此鏈接提供了有關流程的更多信息:http://osdir.com/ml/java.sun.jini/2003-10/msg00204.html

+0

這不是問題的正確說法。問題是你必須調用defaultReadObject()。一旦你這樣做了,讀取你自己的東西的確切字節數並不重要。 – EJP

+0

更正了補充。 – user2219808

2

我也有這個例外。它發生是因爲我使用了兩個線程用於Server類和Client類。我用一個線程來發送和接收對象。然後就可以了。如果您不熟悉​​,這是解決問題的簡單方法。

1

java.io.StreamCorruptedException:無效類型代碼:00

我最近就遇到了這個問題,而不是做什麼OP雖然做到了。做了一個快速谷歌搜索,沒有發現任何太有用的東西,因爲我認爲我解決了它,我正在對我的解決方案發表評論。

TLDR:沒有多個線程同時寫入同一個輸出流(取而代之)。當客戶端嘗試讀取數據時會造成問題。解決方案正在鎖定寫入輸出。

我正在做一些非常類似於OP的東西,製作一個多人遊戲(客戶端 - 服務器模型)。我有一個像OP一樣的線程正在監聽流量。發生了什麼事情,在我的服務器端,該服務器有多個線程同時寫入客戶端的數據流(並不認爲這是可能的,遊戲是半轉彎的基礎)。讀取傳入流量的客戶端線程拋出此異常。爲了解決這個問題,我基本上鎖定了寫入客戶端流的部分(在服務器端),因此服務器端的每個線程在寫入流之前都必須獲得鎖。

相關問題