Search code examples
javamultithreadingsocketsobjectinputstream

Java Client-Server socket, reusing client socket throws "java.io.StreamCorruptedException: invalid type code: AC"


This is my first post at Stack Overflow, so I hope I'm doing it with a minimum of decency.

I tried to implement a simple solution using Java sockets, but I'm having an exception. I'm surely misusing the APIs, but I can't figure out why and where.

The Client needs to send several binary messages to a Server and it (the Client) must reuse the same socket.

In the Server, I've created one thread that does two things: (1) accepts client requests and (2) instantiates a new thread (running a ClientWorker instance) to handle the client requests.

If I just send one message from the Client, everything work fine. Nevertheless, when I try to send multiple messages, during the second message I have a the following exception:

java.io.StreamCorruptedException: invalid type code: AC at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.readObject(Unknown Source) at simple.socketexample.ClientWorker.run(ClientWorker.java:26) at java.lang.Thread.run(Unknown Source)

The exception happens in my ClienWorker class, in the line "Message message = (Message)in.readObject();" Note that the first message is always successfully received by the server.

The following classes are part of a simple example that I've created just to show this error.

The first class is the Message:

package simple.socketexample;

import java.io.Serializable;

public class Message implements Serializable {
    private static final long serialVersionUID = 4473470814745876900L;
    private String text;
    private int number;

    public Message(String text, int number) {
        super();
        this.text = text;
        this.number = number;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "Message [text=" + text + ", number=" + number + "]";
    }
}

This is my Client:

public class Client {
    private final int SERVER_PORT = 3456;
    private final String SERVER_HOST = "localhost";
    private Socket serverSocket;

    public void connect() throws IOException, UnknownHostException {
        serverSocket = new Socket(SERVER_HOST, SERVER_PORT);
    }

    public void disconnect() throws IOException {
        serverSocket.close();
    }

    public void sendMessage(Message message) throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(serverSocket.getOutputStream());
        out.writeObject(message);
        out.flush();
        out.reset();
    }
}

The Server:

public class Server {
    private final int SERVER_PORT = 3456;

    public void start() throws IOException {
        Thread acceptConnectionsThread = new Thread(new Runnable() {
            public void run() {
                // Instantiates the socket
                ServerSocket serverSocket = null;
                try {
                    serverSocket = new ServerSocket(SERVER_PORT);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                // Starts accepting client connections
                while(true) {
                    Socket socketFromClient = null;
                    try {
                        socketFromClient = serverSocket.accept();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    // Create a new "client dedicated thread"
                    ClientWorker clientWorker = new ClientWorker(socketFromClient);
                    Thread clientDedicatedThread = new Thread(clientWorker);
                    clientDedicatedThread.start();
                }
            }
        });

        acceptConnectionsThread.start();

    }
}

My ClientWorker:

public class ClientWorker implements Runnable {
    private Socket socketFromClient;

    public ClientWorker(Socket socketFromClient) {
        super();
        this.socketFromClient = socketFromClient;
    }

    public void run() {
        ObjectInputStream in = null;
        try {
            in = new ObjectInputStream(socketFromClient.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        while(true) {
            try {
                Message message  = (Message)in.readObject();
                System.out.println(message);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                break;
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }
    }
}

And the class that I've used to test this: package simple.socketexample;

import java.io.IOException;

/**
 * Hello world!
 *
 */
public class App {
    public static void main(String[] args) throws Exception {
        // Start the server in a new (background) thread
        Thread serverInBackground = new Thread(new Runnable() {
            public void run() {
                Server server = new Server();
                try {
                    server.start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        serverInBackground.start();

        // Client and connect a client
        Client client = new Client();
        client.connect();

        // Sending one message to the server
        client.sendMessage(new Message("MessageOne", 1));

        // Sending another message to the server
        client.sendMessage(new Message("MessageTwo", 2));

        // Closing the client
        client.disconnect();
    }
}

The problem will probably be in a small detail and the solution may be also be right in front of my nose, but somehow I can't see it. Have anyone faced a similar problem? How did you solve it?

Many thanks and kind regards.


Solution

  • Try this ClientWorker

    public class ClientWorker implements Runnable {
        private Socket socketFromClient;
    
        public ClientWorker(Socket socketFromClient) {
            super();
            this.socketFromClient = socketFromClient;
        }
    
        public void run() {
    
            while(true) {
                ObjectInputStream in = null;
                try {
                    in = new ObjectInputStream(socketFromClient.getInputStream());
                } catch (IOException e) {
                    e.printStackTrace();
                    return;
                }
                try {
                        Message message  = (Message)in.readObject();
                        System.out.println(message);
    
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }
    

    and comment the reset() in Client

        public void sendMessage(Message message) throws IOException {
            ObjectOutputStream out = new ObjectOutputStream(serverSocket.getOutputStream());
            out.writeObject(message);
            out.flush();
    //        out.reset();
        }