17

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

}

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. Commented May 27, 2012 at 18:02
  • addClient(adds the user to an ArrayList of type ClientRepresantative that hold the socket, objectouput and input stream.) it doesn't read anything Commented May 27, 2012 at 18:46
  • 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. Commented May 27, 2012 at 19:48
  • I added the flushing, nothing changed Commented May 27, 2012 at 20:34
  • Do you mind adding your client code where you write objects? Commented May 27, 2012 at 21:22

9 Answers 9

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.
Sign up to request clarification or add additional context in comments.

2 Comments

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..)
@user1420273 Certainly it can, unless you have appropriate synchronization.
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

1 Comment

Thanks!! :) in 2023 with IntelliJ this should be the accepted answer :)
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.

1 Comment

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.
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.

10 Comments

No it can't. That condition causes a ClassNotFoundException.
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!
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.
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.
to @drevicko's point, it is similarly described here.
|
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.

1 Comment

Yes, using synchronized functions works perfectly!
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();
}

Comments

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.

Comments

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

Comments

0

Just doing 'Invalidate Caches and restart' worked for me

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.