4

I am going to write a program over TCP/IP and I should send objects by client or by server, It is going right when I want to send or receive strings but when I am trying to read an object:

private Socket client;

public ThreadedClient(Socket client) {
    this.client = client;
}

@Override
public void run() {
        try {
            ObjectInputStream objIn = new ObjectInputStream(client.getInputStream());
            while(true){
                try {
                    Object fromClient = objIn.readObject();

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

I receive an exception:

java.io.StreamCorruptedException: invalid stream header: 306E6165
    at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
    at java.io.ObjectInputStream.<init>(Unknown Source)
    at org.bihe.serverSocket.ThreadedClient.run(Server.java:137)
    at java.lang.Thread.run(Unknown Source)

and it refers to this line:

    ObjectInputStream objIn = new ObjectInputStream(client.getInputStream());

It is my server code:

            ServerSocket ss = new ServerSocket(8800);
            while(true){
                Socket newClient = ss.accept();

                System.out.println(">>>> Client number " + (++counter) + " connected.");
                OutputStream outputStream = newClient.getOutputStream();
                PrintWriter sender = new PrintWriter(outputStream);
                sender.println(true);
                sender.flush();
                ThreadedClient client = new ThreadedClient(newClient);
                clients.add(client);
                new Thread(client).start();

Client side code:

sc = new Socket("127.0.0.1", 8800);
            InputStream inputStream = sc.getInputStream();
            Scanner scanner = new Scanner(inputStream);
            boolean s = scanner.nextBoolean();
            if(s){
                System.out.println("Client connected successfully.");
                return true;
            }else{
                System.out.println("Ohhh, Some problem happened, try again later!");
            }

Can anyone explain me what is happening, what is this exception and why I received this exception?

Naeem Baghi
  • 673
  • 1
  • 11
  • 26

3 Answers3

5

If you want to send object over network you must serialize your objects.

Check this question: How To send an object over TCP in Java

Java Serialization: Serialization

You could do it like this:

import java.net.*;  
import java.io.*;  

class testobject implements Serializable {  
  int value;  
  String id;  

  public  testobject(int v, String s ){  
       this.value=v;  
       this.id=s;  
    }  

}  

public class SimpleServer  {  
  public static void main(String args[]) {  
  int port = 2002;  
  try {  
    ServerSocket ss = new ServerSocket(port);  
    Socket s = ss.accept();  
    InputStream is = s.getInputStream();  
    ObjectInputStream ois = new ObjectInputStream(is);  
    testobject to = (testobject)ois.readObject();  
    if (to!=null){System.out.println(to.id);}  
    System.out.println((String)ois.readObject());  
    is.close();  
    s.close();  
    ss.close();  
}catch(Exception e){System.out.println(e);}  
}  
}  

import java.net.*;  
import java.io.*;  
   public class SimpleClient {  
   public static void main(String args[]){  
     try{  
     Socket s = new Socket("localhost",2002);  
     OutputStream os = s.getOutputStream();  
     ObjectOutputStream oos = new ObjectOutputStream(os);  
     testobject to = new testobject(1,"object from client");  
     oos.writeObject(to);  
     oos.writeObject(new String("another object from the client"));  
     oos.close();  
     os.close();  
     s.close();  
   }catch(Exception e){System.out.println(e);}  
  }  
}  
Community
  • 1
  • 1
Attila
  • 2,555
  • 2
  • 23
  • 34
  • There is no evidence here that the object being sent isn't Serializable. – user207421 Jan 12 '14 at 09:36
  • 1
    I want to send a client that implements serializable and have a serialversionUID, and in some cases I want to send a string to server, but it is not going to the line after ObjectInputStream objIn = new ObjectInputStream(client.getInputStream()); I think it is not about serializable, I understand your code, but I cannot understand why I received this exception. – Naeem Baghi Jan 12 '14 at 09:43
  • @AttilaBujáki You do not answered my question, but your code was helpful, and I thank you for your time – Naeem Baghi Jan 12 '14 at 10:22
3

Just get rid of sending and receiving the Boolean. It's redundant. If there was some problem creating the connection, the socket wouldn't get created: an exception would be thrown instead. You're confusing everything with multiple streams on the same socket. Don't do that.

In your read-object loop, you need to catch EOFException separately, and when you get it, close the socket and exit the loop. If you get any other IOException, log it, close the socket, and exit the loop.

user207421
  • 289,834
  • 37
  • 266
  • 440
  • I have found my problem, You were right, I removed unneeded codes, so I understand the problem. It was because I was trying to send a string through a printwriter but when I changed the code I tried to receive that String by a objectInputStream and it causes the exception, I changed the printwriter to objectOutputStream and the problem solved, Thank you all, but I do not understand why you said when I get EOFException I should close the loop, I have a project like twitter, and I am at the start point. I should send and received objects when client running, why should I close the socket? – Naeem Baghi Jan 12 '14 at 10:06
  • 1
    1. No. It was because you were using multiple streams on the same socket, which only works if none of them is buffered ... but it still isn't a good idea. 2. When you get EOFException it means the peer has closed the connection. There is no more data. There will never be any more data. If you keep reading you will just keep getting EOFException. Don't. Break out of the loop. – user207421 Jan 12 '14 at 10:07
  • for the first part, what should I do? You are saying that it is not a good idea to send all I want by an arraylist and through objectOutputStream, then I catch the first member of arrayList that is a string and by its value send the second member that may be a client or a string to do something in the server side? Do you have a better idea? for the second part: I got it, Thank you, it means the client signed out, So I should close the socket, am I right? – Naeem Baghi Jan 12 '14 at 10:18
  • 1
    1. I said what I said. Get rid of sending and receiving the Boolean. Get rid of the `Scanner` and the `PrintWriter.` Do everything through a single stream. 2. I did mention closing the socket, several times. – user207421 Jan 12 '14 at 11:46
1

If you'd like to achieve good performance and send object then you definitely should use Google Protobuf

It allows you to define messages in simple .proto files. Then you use bundled compiler to generate Java classes which will be serialized and sent.

Also better idea is to use Netty over plain Java sockets. This prevent you from writing a lot of boilerplate code and define simple serialization/deserialization pipelines. Take a look at user-guide.

Jakub Kubrynski
  • 12,678
  • 4
  • 56
  • 80