0

I am developing a multiplayer snake game. The game seems to be running fine except it often(not every time) randomly throws the java.io.StreamCorrupted Exception type code :AC The full StackTrace of the same is given below.

java.io.StreamCorruptedException: invalid type code: AC
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readArray(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at mycode.ConnectionManager.otherRunMethod(ConnectionManager.java:231)
at mycode.ConnectionManager$1.run(ConnectionManager.java:289)
at java.lang.Thread.run(Unknown Source)

The Client side code where the error is generated is given below:

void otherRunMethod() {
    try {
        while (true) {
            boolean gameup = false;
            objin = new ObjectInputStream(socket.getInputStream());
            Object insnake = objin.readObject();
            if (((Snake) insnake).player.length() >= 9) {
                if (((Snake) insnake).player.substring(0, 8).equals(
                        "Resigned")) {
                    String[] s = ((Snake) insnake).player.split(",");
                    map.remove(s[1]);
                    continue;
                } else if (((Snake)insnake).player.substring(0, 10)
                        .equals("food_eaten")) {
                    String[] s = ((Snake) insnake).player.split(",");
                    Game.foodx = Integer.parseInt(s[1]);
                    Game.foody = Integer.parseInt(s[2]) + 35;
                    objin = new ObjectInputStream(socket.getInputStream());
                    insnake = objin.readObject();
                    if(((Snake)insnake).score>highestscore){
                        highestscore=((Snake)insnake).score;
                        if(highestscore>=100 && highestscore<200)
                            levelUp(2);
                        else if(highestscore>=200){
                            levelUp(4);
                        }
                    }
                    if (s.length == 4) {
                        System.out.println(s[3]);
                        if (s[3].equals("game_up")) {
                            gameup=true;
                        }
                    }
                }
            }
            Snake temp = new Snake((Snake) insnake);
            map.remove(temp.player);
            map.put(temp.player, temp);
            if(temp.gameover){
                allPlayersEliminated();
            }
            findPos();
            game_UpCheck(gameup);
            Thread.sleep(10);
        }
    } catch (java.net.SocketException s) {
        JOptionPane.showMessageDialog(null, "Server Closed", "ERROR",
                JOptionPane.ERROR_MESSAGE);
        System.exit(0);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

The corresponding server side code for the same is as follows:

    void relay(Snake move) {
    boolean foodeaten = false;
    Snake snake = move;
    try {
        if (move != null && move.player.length() > 9) {
            if (move.player.equals("food_eaten")) {
                move.player = move.player + ","
                        + (Snakeserver.randomGenerator.nextInt(100) * 6)
                        + ","
                        + (Snakeserver.randomGenerator.nextInt(100) * 6);
                foodeaten = true;
                snake = (Snake) objin.readObject();
                int rows = Snakeserver.score.getModel().getRowCount();
                int row = 1;
                for (int i = 0; i < rows; i++) {
                    if (((Snake) snake).player
                            .equals((String) Snakeserver.score.getModel()
                                    .getValueAt(i, 0))) {
                        row = i;
                        break;
                    }
                }
                if (snake.score >= 300)
                    move.player += "," + "game_up";
                Snakeserver.score.getModel()
                        .setValueAt(snake.score, row, 1);
            } 
        }

        if (move.gameover) {
            int rows = Snakeserver.score.getModel().getRowCount();
            int row = 1;
            for (int i = 0; i < rows; i++) {
                if (snake.player.equals((String) Snakeserver.score
                        .getModel().getValueAt(i, 0))) {
                    row = i;
                    break;
                }
            }
            Object temp = Snakeserver.score.getModel().getValueAt(row,
                    1);
            temp += "  GAME OVER";
            Snakeserver.score.getModel().setValueAt(temp, row, 1);
        }

        for (Snake name : map.keySet()) {
            if (name != null) {
                if (name.player.equals(snake.player)) {
                    name.copyValues(snake);
                }
                objout = new ObjectOutputStream(map.get(name)
                        .getOutputStream());
                objout.writeObject(move);
                objout.flush();
                if (foodeaten) {
                    objout = new ObjectOutputStream(map.get(name)
                            .getOutputStream());
                    objout.writeObject(snake);
                    objout.flush();
                }
            }
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Actually I don't know where the problem lies so I have perhaps dumped more code than necessary.

user207421
  • 305,947
  • 44
  • 307
  • 483
Sohaib
  • 4,556
  • 8
  • 40
  • 68
  • In your `otherRunMethod()`s `while`-loop, you're creating a new `OutputStream` for every iteration and are writing to a non-recreated `InputStream`. See the question I linked above. – Lukas Knuth Apr 13 '13 at 10:27
  • Thanks Lukas. Could you please elaborate a bit. I was searching for an error of a similar kind. – Sohaib Apr 13 '13 at 10:30
  • For starters, move the `InputStream` creation out of your loop and only *use* it inside the loop. – Lukas Knuth Apr 13 '13 at 10:41
  • There are multiple player. I have to create a separate OutputStream for each of them. That is why multiple initialization are done in the server method. In the client method if I move it out of the loops it throws a StreamCorrupted Exception always instead of the casual error Im getting right now. – Sohaib Apr 13 '13 at 10:45

2 Answers2

0

I finally found the solution to my problem after digging around for a few hours. In the server side code see the following piece of code:

for (Snake name : map.keySet()) {
        if (name != null) {
            if (name.player.equals(snake.player)) {
                name.copyValues(snake);
            }
            objout = new ObjectOutputStream(map.get(name)
                    .getOutputStream());
            objout.writeObject(move);
            objout.flush();
//rest of code goes here. Closing brackets as above.

If I write the line

 objout = new ObjectOutputStream(map.get(name).getOutputStream());

before the compound statement

if (name.player.equals(snake.player)) {
            name.copyValues(snake);
}

I seem to get rid of the StreamCorrupted Exception. Any suggestions as to why this is happening would be most welcome.

Sohaib
  • 4,556
  • 8
  • 40
  • 68
  • You've been told why its happening. You should use the same streams for the life of the socket, not create new ones per write. – user207421 Apr 14 '13 at 01:41
  • That does not work. Cannot work actually because at the server side there is a single output stream that needs to send to multiple clients. So it "HAS" to be instantiated multiple times. (Please see my map object. As I said it holds . So different sockets need different output streams.) So if I do not instantiate the input streams per read at the client side it obviously leads to StreamCorrupted Exception. – Sohaib Apr 14 '13 at 08:26
  • It is implied by what I said above that you must instantiate the corresponding `ObjectInputStreams` once per socket as well. If you can manage a socket per connection, you can manage a pair of streams as well. – user207421 Apr 14 '13 at 09:54
  • Thanks for the suggestion EJP. Now consider the following situation. I receive a message from client 1. There are a total of say 10 clients. Now this message needs to be relayed to all 10 clients. Now by what you suggest I am allowed to instantiate my OutputStream just once. So how do I get it across to all 10 clients. They do have different addresses right? You people are pros at java and sockets I think I cannot explain myself any better. What you are suggesting seems impossible. If I instantiate my stream once only how do I relay it to all my 10 clients? – Sohaib Apr 14 '13 at 14:09
  • I'll try it one more time. You must instantiate one ObjectInputStream and one ObjectOutputStream *per Socket.* It does work, but you have to actually do it first. Hint: change your Map to map to an object that contains the socket *and the ObjectOutputStream.* – user207421 Apr 15 '13 at 00:23
  • Oh okay now I get your point. You mean to say to maintain multiple objectoutputstream. Thanks for the suggestion would try that out although my current code is working fine as of now. – Sohaib Apr 15 '13 at 01:54
  • I meant to say 'one `ObjectOutputStream` per `Socket`', and I did say it. 'Multiple `ObjectOutputStreams` is not an acceptable or even an accurate paraphrase: it also describes what you are already doing – user207421 Apr 15 '13 at 04:51
0

I too faced same exception and issue as explained above, was, while writing(sending) msg(object), I was creating new OutputObjectStream, as below

//client or server side
while(true)
{
    ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
    out.writeObject(some_msg_object);
}

/* but while reading(receiving), I was not creating new inputObjectReader
ie */
//on other side
while(true)
Message msgReceived = (Message)inputObjectReader.readObject();

and this resulted above exact same education,

therefore, if sending msg, by creating new OutputStream, receive it by creating new InputStream viceversa, is sending using same already created OutputStream receive by already created InputStream.....

user2978111
  • 23
  • 12