java.io.StreamCorruptedException: invalid type code: 00
Asked Answered
B

8

16

So basically im writing a client-server multiplayer game. I have a SeverCommunicationThread that creates a gameThread if he receives a RequestForGame creates a gameThread. When i send a RequestForGame exception is thrown java.io.StreamCorruptedException: invalid type code: 00 I assume it's because both threads try to read the same ObjectInputStream, I don't have much understanding about how it works, i just know how to use it. Could you help me understand what's the problem and how to fix it? Thanks :)

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

}
}    

the model.addClient method though i don't think the problem is here

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

The client side proxy that sends objects to server, the methods are triggered by user actions in 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();
    }
}

}

Beamer answered 27/5, 2012 at 16:58 Comment(11)
What is ServerModelManager doing when you call model.addClient(nickname, connectionSocket,outToClient,inFromClient);? There may be code within it that is corrupting the stream.Waxplant
addClient(adds the user to an ArrayList of type ClientRepresantative that hold the socket, objectouput and input stream.) it doesn't read anythingBeamer
Alright. Also, you should flush ObjectOutputStreams after constructing them to ensure that the header is sent. That may be the reason you are receiving that error; the stream header hasn't gone through yet. Flush the ObjectOutputStream on both the client and the server after creation.Waxplant
I added the flushing, nothing changedBeamer
Do you mind adding your client code where you write objects?Waxplant
Sorry, I meant the code where the client writes objects to the server.Waxplant
@Vulcan The ObjectOutputStream flushes itself during construction. I've been giving that advice for years too, but it isn't necessary. It is necessary to construct it before the ObjectInputStream, preferably at both ends to avoid accidents.Moolah
@Beamer Constructing new Strings around string literals is wasteful. Don't do that; use writeUnshared() instead.Moolah
what exactly do you mean by "Constructing new Strings around string literals" could you clarify please?Beamer
@Beamer new String("abc") is semantically identical to "abc" except that it refers to a different, redundant, object. Just use "abc".Moolah
I have the same problem.How did you solve this problem?Stricklin
M
10

This problem can happen if you:

  1. construct a new ObjectInputStream or ObjectOutputStream over the same socket instead of using the same ones for the life of the socket (invalid type code AC);
  2. use another kind of stream over the same socket as well; or
  3. use the object streams to read or write something that isn't an object and get that process out of sync.
Moolah answered 27/5, 2012 at 23:20 Comment(2)
I create the ObjectOutputStream first at both sides(Proxy,ServerCommunicationThread). I construct it only once and then just send a reference to it to the other Thread. I don't use any other kind of stream. The only thing that comes to mind is that i'm trying to read an object from the same ObjectInputStream in 2 Threads at the same time.(ServerCommunicationThread,ServerGameThread) Can this be the problem? (from the location of the exception i would assume so..)Beamer
@Beamer Certainly it can, unless you have appropriate synchronization.Moolah
I
6

In intellij this is how I solved for Java. Go to build> gradle enter image description here

then change the java version to lower one. enter image description here

Interrogative answered 29/6, 2023 at 14:27 Comment(1)
Thanks!! :) in 2023 with IntelliJ this should be the accepted answer :)Flamen
H
5

There's another possibility that I ran across where if you implement a custom deserialization routine for a class by adding this method:

private void readObject( ObjectInputStream objectInputStream ) throws IOException

then objectInputStream.defaultReadObject() must be called and called before any further reads of the input stream to properly initialise the object.

I missed this and despite the object returning without an exception being thrown it was the next read of the object stream that confusingly raised the invalid type code exception.

This link provides further information on the process: http://osdir.com/ml/java.sun.jini/2003-10/msg00204.html.

Heyman answered 21/12, 2014 at 1:47 Comment(1)
This is not a correct statement of the problem. The issue is that you must call defaultReadObject(). Once you've done that it isn't important that you read the exact number of bytes of your own stuff.Moolah
R
4

This can also happen if the JVM reading the serialized object does not have the correct class/jar files for the object. This usually results in a ClassNotFoundException, but if you have different jar/class versions and the serialVersionUID was not changed between versions, a StreamCorruptedException is produced. (This exception may also be possible if there is a class name conflict. e.g.: a jar containing a different class with the same full class name, though they probably also need the same serilVersionUID).

Check that the client side has the correct versions of jars and class files.

Recitation answered 7/11, 2012 at 4:14 Comment(10)
No it can't. That condition causes a ClassNotFoundException.Moolah
I made this answer as I had successfully fixed the error in the question by installing the correct jar files. I believe in my case I had the wrong versions (and the version UID was not properly maintained), though it was a while ago now... It may also be possible with class name conflicts? @ejp I'll amend my answer to indicate jar file versions - fell free to remove your down vote, it doesn't motivate one to provide others with the benefit of ones experiences!Recitation
If you have a serialVersionUID mismatch you get an exception that explicitly says so, listing both the expected and the actual serialVersionUIDs. You do not get a StreamCorruptedException that says unexpected type code 0x00. Mis-diagnoses aren't beneficial to anybody.Moolah
Unfortunately the world is not perfect, and not everybody maintains serialVersionUID's properly. There was not a serialVersionUID mismatch - it had not been properly maintained between versions. As I said, I had the error stated in the question and solved it by installing the correct version. This is NOT a misdiagnosis! It is a possible cause of this error.Recitation
Just in case it's not clear, by 'not properly maintained' I mean to say that the serialVersionUID of a class was not changed between versions. Thus the version UID's matched, and the exception raised was a StreamCorruptedException, since the ObjectInputStream did not find elements corresponding to those it was expecting. Believe me, it took some time to figure that out, and this SO question was one of the places I looked for the answer - hence I provide it here for others who encounter a similar situation.Recitation
to @drevicko's point, it is similarly described here.Bencher
@Recitation There is nothing 'proper' about changing the serialVersuonUID between versions. This is merely a very widely spread misconception. It appears nobody has actual read the Versioning chapter of the Object Serialization Specification, or they wouldn't be deliberately causing unnecessary incompatibilities and extra work for themselves with this bizarre practice.Moolah
@dreveo And your assertion that class changes can produce a StreamCorruptedExceptuon remains false.Moolah
@EJP Did you test the scenario I presented? I reported this because it DID happen. Perhaps in recent versions of Java it is no longer possible, but at the time I can assure you it was.Recitation
it isn't necessary to test it. The Object Serialization Specification provides that adding fields to a class is compatible under Serialization.Moolah
C
3

I too had this exception. It occurred because I used two threads for Server class and Client class. I used one thread for object sending and receiving thing. Then it was ok. This is easy way to solve the problem if you are not familiar with synchronized.

Charlean answered 7/1, 2015 at 13:57 Comment(1)
Yes, using synchronized functions works perfectly!Keep
P
2

If ObjectInputStream is constructed only once and then just passed a reference of it to the other Thread then simply enclose the access of this object inside synchronized block to make sure that only one thread can access this object at a time.

Whenever you are reading from ObjectInputStream just access it inside the synchronized block if it is shared between multiple threads.


Sample code:(do it for all the occurrences of readObject())

...
String nickname = null;
synchronized (inFromClient) {
    nickname = (String) inFromClient.readObject();
}
Patrizius answered 10/5, 2014 at 12:4 Comment(0)
K
1

java.io.StreamCorruptedException: invalid type code: 00

I recently ran into this problem, not doing what OP did though. Did a quick google search and didn't find anything that was too helpful and because I think I solved it I am making a comment with my solution.

TLDR: Don't have multiple threads write to the same output stream at same time (instead take turns). Will cause issues for when client side tries to read the data. Solution is putting a lock on the writing to output.

I am doing something very similar to OP, making a multiplayer (client-server model) game. I have a thread like OP that is listening for traffic. What was happening, in my server side was that server had multiple threads that were writing to a client's stream at the same time (didn't think it was possible, game was semi turn base). Client side thread that was reading the incoming traffic was throwing this exception. To solve this I basically put a lock on the part that wrote to the client's stream (on server side) so each thread in server side would have to obtain the lock before writing to the stream.

Kirstiekirstin answered 15/6, 2017 at 2:27 Comment(0)
H
0

My problem is gradle JVM is configed incorrect. Please check that compatible JDK is used in Settings

1. File | Setting | Build, Execution, Deployment | Build Tools | Gradle | Gradle JVM (Here is my problem)

2. Please select the correct your own JDK directory installation in the local computer (default dir in windows is located at the path "C:\Program Files\Java\jdk-17")

Hope to help you all

Heinrik answered 13/7, 2023 at 2:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.