Запись объекта в ObjectOutputStream не работает

#java #sockets #objectoutputstream

#java #сокеты #objectoutputstream

Вопрос:

я пишу (тестирую) простое клиент-серверное приложение, в котором мне нужно отправить некоторый объект через ObjectOutputStream сокета, а затем прочитать его через ObjectInputStream сокета. Проблема в том, что метод ObjectOutputStream writeObject не работает должным образом (или, возможно, я делаю что-то неправильно …). Я выполняю запись и чтение одним и тем же методом.

java -версия:

 java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)
  

Это мой код:

ServerTest.java

 ExecutorService tp = Executors.newFixedThreadPool(2);
public ServerTest(String info) {
    System.out.println("SERVER TEST HAVE BEEN STARTED FROM "   info);
    try {
        System.out.println("Starting server ...");
        tp.submit(new ServerTask());
        System.out.println("Server started ...");
        Thread.sleep(1000);
        System.out.println("Starting client ...");
        tp.submit(new Client(new Socket("localhost", 3333)));
        System.out.println("Client started at localhost on port 3333 ...");
    } catch (IOException | InterruptedException ex) {
        Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
    } 
}
public static void main(String[] args) {
    try {
        new ServerTest("SERVER TEST MAIN STATIC METHOD");
        Thread.sleep(100000);
    } catch (InterruptedException ex) {
        Logger.getLogger(ServerTest.class.getName()).log(Level.SEVERE, null, ex);
    }
}
  

ClientTask.java (реализует Runnable )

 private Socket socket;
private ObjectOutputStream oos;
private ObjectInputStream ois;    
public ClientTask(Socket socket) {
    System.out.println("CLIENT TASK SOCKET : "   socket);
    this.socket = socket;
    try {
        oos = new ObjectOutputStream(socket.getOutputStream());
        oos.flush();
        ois = new ObjectInputStream(socket.getInputStream());
    } catch (IOException ex) {
        Logger.getLogger(ClientTask.class.getName()).log(Level.SEVERE, null, ex);
    }
}

@Override
public void run() {
    System.out.println("client task running ...");
    for (int i = 0; i < 1; i  ) {
        try {
            Thread.sleep(1000);
            SimpleObject so = new SimpleObject(100, "test_str");
            System.out.println("Trying to serialize object into output stream...");
            System.out.println("Object to be written "   so.toString());
            oos.writeObject(so);
            oos.flush();
            System.out.println("Check if the object had been serialized properly ...");
            System.out.println("Bytes in stream : "   ois.available());
            if (ois.available() <= 0) {
                System.out.println("Object had not been serialized ...");
                continue;
            }
            System.out.println("Trying to deserialize object from input stream ...");
            SimpleObject desObj = (SimpleObject) ois.readObject();
            System.out.println("Read object: "   desObj.toString());
            System.out.println("Aborting from method ...");
        } catch (InterruptedException ex) {
            Logger.getLogger(ClientTask.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(ClientTask.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ClientTask.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                ois.close();
                oos.close();
            } catch (IOException ex) {
                Logger.getLogger(ClientTask.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    System.out.println("Exiting client task ...");
}
  

ServerTask.java (реализует Runnable)

 ExecutorService tp = Executors.newFixedThreadPool(10);
@Override
public void run() {
    System.out.println("Server task run start ...");
    try {
        ServerSocket ss = new ServerSocket(3333);
        for (;;) {
            System.out.println("Server socket start ...");
            Socket s = ss.accept();
            s.setSoTimeout(0);
            System.out.println("Connection: "   s.getInetAddress().toString()   " "   s.getPort());
            System.out.println("Starting client task ...");
            tp.submit(new ClientTask(s));
            System.out.println("Client task started ...");
            System.out.println("Server socket end ...");
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    System.out.println("Server task run end ...");
}
  

Client.java (реализует Runnable)

 private Socket socket;
private ObjectOutputStream oos;
private ObjectInputStream ois;
public Client(Socket socket) {
    System.out.println("CLIENT SOCKET : "   socket.toString());
    this.socket = socket;
    try {
        oos = new ObjectOutputStream(socket.getOutputStream());
        oos.flush();
        ois = new ObjectInputStream(socket.getInputStream());
    } catch (IOException ex) {
        Logger.getLogger(ClientTask.class.getName()).log(Level.SEVERE, null, ex);
    }
}

@Override
public void run() {
    for (int i = 0; i < 10; i  ) {
        //System.out.println("client running ...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
  

SimpleObject.java (реализует Serializable)

 private static final long serialVersionUID = 4L;
private Integer integer;
private String string;
public SimpleObject(Integer integer, String string) {
    this.integer = integer;
    this.string = string;
}
//getters,setters, toString method ...
  

Вывод

 run:
SERVER TEST HAVE BEEN STARTED FROM SERVER TEST MAIN STATIC METHOD
Starting server ...
Server started ...
Server task run start ...
Server socket start ...
Starting client ...
CLIENT SOCKET : Socket[addr=localhost/127.0.0.1,port=3333,localport=57703]
Connection: /127.0.0.1 57703
Starting client task ...
CLIENT TASK SOCKET : Socket[addr=/127.0.0.1,port=57703,localport=3333]
Client started at localhost on port 3333 ...
Client task started ...
Server socket end ...
Server socket start ...
client task running ...
Trying to serialize object into output stream...
Object to be written SimpleObject{integer=100, string=test_str}
Check if the object had been serialized properly ...
Bytes in stream : 0
Object had not been serialized ...
Exiting client task ...
  

Это простое приложение, но оно не работает… я не могу понять, почему. Пожалуйста, помогите мне.

Комментарии:

1. Ваш объект SimpleObject реализует сериализуемый интерфейс.

2. @VinayAvasthi да.

3. Строка System.out.println(«Байты в потоке: » ois.available());, которая показывает байты входного потока сокета клиентской задачи. Это покажет количество доступных байтов, отправленных сервером, которое не будет иметь ничего общего с тем, что было записано в выходной поток сокета.

4. Кроме того, вы хотите, чтобы и клиент, и сервер использовали одни и те же входные потоки? Я бы ожидал, что клиент и сервер будут находиться в разных потоках (или в разных процессах Java), и в этом случае поток вывода клиента будет отображаться на поток ввода сервера, а поток ввода клиента будет отображаться на поток вывода сервера. Вот хороший пример для подражания: baeldung.com/a-guide-to-java-sockets (Примечание: Это не предназначено для поддержки Baeldun. Но пример хороший.)

5. @ThomasBitonti я записал как запись, так и чтение объекта в один метод просто для упрощения тестирования… но теперь я попытался разделить его на разные потоки (и классы), и это работает. Большое вам спасибо, если вы опубликуете свой комментарий в качестве ответа, я пометлю его как принятый ответ.

Ответ №1:

Вы хотите, чтобы и клиент, и сервер использовали одни и те же входные потоки? Я бы ожидал, что клиент и сервер будут находиться в разных потоках (или в разных процессах Java), и в этом случае поток вывода клиента будет отображаться на поток ввода сервера, а поток ввода клиента будет отображаться на поток вывода сервера. Вот хороший пример для подражания: baeldung.com/a-guide-to-java-sockets (Примечание: Это не предназначено для поддержки Baeldun. Но пример хороший.)