Question

package com.common.net;

import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Random;

public abstract class PacketCommunicator implements Runnable {

    private Object lastCommandSent;
    private Object lastCommandReceived;
    private Object lastPacketReceived;
    private Object lastPacketSent;

    protected ObjectInputStream in;
    protected ObjectOutputStream out;
    protected Socket socket;
    private boolean connected;
    protected boolean encryptionEnabled = false;
    protected String key = "default";

    public HashMap<String, Object> data;

    protected int sentPackets = 0;
    protected int receivedPackets = 0;

    public String getIP() {
        return socket.getInetAddress().toString();
    }

    public abstract void disconnect();

    public abstract void broadcast(String cmd, String data);

    public abstract void broadcast(Object packet);

    /**
     * This is used for the LPacket system which is not recommended for
     * sensitive data since LPacket's can be decompiled and the functions for
     * both server and client are visible.
     * 
     * @param packet
     */
    public abstract void packetReceived(Object packet);

    /**
     * This is good for sensitive data
     * 
     * @param packetID
     *            ID of packet
     * @param cmd
     *            Labeling command
     * @param data
     */
    public abstract void packetReceived(String cmd, String data);

    public void toggleEncryption() {
        encryptionEnabled = !encryptionEnabled;
    }

    public boolean isConnected() {
        return connected;
    }

    public void flush() {
        try {
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Sends the LPacket to this client
     * 
     * @param packet
     */
    public void sendPacket(Object packet) {
        try {
            sentPackets++;
            out.flush();
            out.writeObject(packet);
            this.lastPacketSent = packet;
            out.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendPacket(String cmd, String data) {
        try {

            sentPackets++;

            String s = cmd + ":" + sentPackets + "::" + data;
            out.flush();
            if (encryptionEnabled) {
                out.writeObject(encrypt(key, s));
            } else {
                out.writeObject(s);
            }
            out.flush();
            lastCommandSent = s;

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // Constructor class for game client
    public PacketCommunicator(String server, int port) throws IOException {
        this(new Socket(server, port), false);
    }

    /**
     * 
     * @param socket
     * @param onServer
     *            The Packet Communicator on the server MUST create the input
     *            stream first This constructor is used for the server
     */
    public PacketCommunicator(Socket socket, boolean onServer) {
        this.socket = socket;
        data = new HashMap<String, Object>();

        try {

            if (onServer) {
                in = new ObjectInputStream(socket.getInputStream());
                out = new ObjectOutputStream(socket.getOutputStream());
            } else {
                out = new ObjectOutputStream(socket.getOutputStream());
                in = new ObjectInputStream(socket.getInputStream());
            }

            connected = true;

        } catch (IOException e) {
            e.printStackTrace();
        }

        Thread t = new Thread(this);
        t.start();

    }

    /*
     * @param Manually closes the connection
     */
    public void closeConnection() {
        connected = false;
        disconnect();
        try {
            out.flush();
            out.close();
            in.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (this.isConnected()) {
            try {

                Object packet = in.readObject(); <---Line 174
                receivedPackets++;
                if (packet instanceof String) {
                    this.lastCommandReceived = packet;
                    String packetString = packet.toString();
                    if (encryptionEnabled) {
                        packetString = decrypt(key, packetString);
                    }

                    String cmd = packetString.substring(0, packetString.indexOf(":"));

                    int packetID = Integer.parseInt(packetString.substring(packetString.indexOf(":") + 1,
                            packetString.indexOf("::")));

                    String data = packetString.substring(packetString.indexOf("::") + 2);

                    // FServer.log(packetString);
                    if (packetID == receivedPackets) {

                    } else {
                    }

                    packetReceived(cmd, data);
                } else {
                    this.lastPacketReceived = packet;
                    this.packetReceived(packet);
                }
            } catch (StreamCorruptedException e) {
                connected = false;
                e.printStackTrace();
            } catch (EOFException e) {
                // This usually happens when someone manually disconnects,
                // really not too big of an issue
                connected = false;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SocketException e) {
                // Closed client
                connected = false;
            } catch (IOException e) {
                connected = false;
                e.printStackTrace();
            }
        }
        System.out.println("Last packet sent: " + lastPacketSent);
        System.out.println("Last packet received: " + lastPacketReceived);

        System.out.println("Last command sent: " + lastCommandSent);
        System.out.println("Last command received: " + lastCommandReceived);
        disconnect();
    }

    public static String encrypt(String key, String text) {
        long finalKey = 0;
        for (int i = 0; i < key.length(); i++) {
            long tempKey = key.charAt(i);
            tempKey *= 128;
            finalKey += tempKey;
        }
        Random generator = new Random(finalKey);
        String returnString = "";
        for (int i = 0; i < text.length(); i++) {
            if (text.charAt(i) == ' ') {
                returnString += text.charAt(i);
            } else {
                int temp = text.charAt(i);
                temp += generator.nextInt(95);
                if (temp > 126) {
                    temp -= 95;
                }
                returnString += (char) temp;
            }
        }
        return returnString;
    }

    public static String decrypt(String key, String text) {
        long finalKey = 0;
        for (int i = 0; i < key.length(); i++) {
            long tempKey = key.charAt(i);
            tempKey *= 128;
            finalKey += tempKey;
        }
        Random generator = new Random(finalKey);
        String returnString = "";
        for (int i = 0; i < text.length(); i++) {
            if (text.charAt(i) == ' ') {
                returnString += text.charAt(i);
            } else {
                int temp = text.charAt(i);
                temp -= generator.nextInt(95);
                if (temp < 36) {
                    temp += 95;
                }
                if (temp > 126) {
                    temp -= 95;
                }
                returnString += (char) temp;
            }
        }
        return returnString;
    }

}


java.io.StreamCorruptedException: invalid type code: 00
    at java.io.ObjectInputStream$BlockDataInputStream.readBlockHeader(Unknown Source)
    at java.io.ObjectInputStream$BlockDataInputStream.refill(Unknown Source)
    at java.io.ObjectInputStream$BlockDataInputStream.read(Unknown Source)
    at java.io.DataInputStream.readInt(Unknown Source)
    at java.io.ObjectInputStream$BlockDataInputStream.readInt(Unknown Source)
    at java.io.ObjectInputStream.readInt(Unknown Source)
    at java.util.ArrayList.readObject(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at java.io.ObjectStreamClass.invokeReadObject(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.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 com.common.net.PacketCommunicator.run(PacketCommunicator.java:174)
    at java.lang.Thread.run(Unknown Source)

Basically, sometimes. And I mean only sometimes (25% of the time) does this error show up. It happens when I try to send this from the server:

public void teleportToMap(String mapName, int tileX, int tileY) {
    player.map = mapName;
    currentMap = Server.mapHandler.getMap(mapName);

    MapPacket mp = new MapPacket(currentMap, tileX, tileY);
    sendPacket(mp);

}

And now here's the snippet for the MapPacket. MapPacket extends PacketToClient which basically just calls applyToClient on the PacketToClient when received from the objectinputstream.

package com.common.packet.packets.client;

import com.badlogic.gdx.Gdx;
import com.client.Forest;
import com.client.net.ServerConnection;
import com.client.scenes.GameScene;
import com.common.map.Map;
import com.common.movable.Movable;
import com.common.packet.PacketToClient;

import java.util.ArrayList;

public class MapPacket extends PacketToClient {

    private static final long serialVersionUID = 1L;

    String mapName;
    ArrayList<Movable> ground;

    int tileX, tileY;

    public MapPacket(Map map, int tileX, int tileY) {
        this.mapName = map.name;
        this.ground = map.getGround();
        this.tileX = tileX;
        this.tileY = tileY;
    }

    @Override
    public void applyPacketToClient(ServerConnection server) {
        Gdx.app.postRunnable(new Runnable() {
            public void run() {
                GameScene.currentMap = null;
                GameScene.mapRenderer.setCurrentMap(null);
                Map map = ServerConnection.loadMapFromServer(mapName);
                map.setGround(ground);
                GameScene.mapRenderer.setCurrentMap(map);
                GameScene.currentMap = map;
                Forest.player.setTilePosition(tileX, tileY);
            }
        });
    }

}

I did quite a bit of research from this, but I keep coming up cold. I also occasionally get Stream active exceptions.

Was it helpful?

Solution

I would say you're writing to or reading from the streams simultaneously in two or more threads. That's the only explanation for 'stream active', and it may well explain the other problem too.

NB You don't need that business of creating the streams in different orders. Always create the ObjectOutputStream first. You should create those streams in the run() method of your Runnable, not where you're doing it: it involves blocking I/O which should only be done in that thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top