ObjectInputStream всегда извлекает пустой список

Я работаю над проектом клиент-сервер (вы можете назвать его «Широковещательный чат»), но у меня возникла проблема с ObjectInputStream. Он всегда возвращает мне пустой список, я нашел решение, но не знаю, почему оно работает...

Это код с ошибками (проверьте серверную функцию sendMsg()):

СЕРВЕР:

public class CoreServer implements Runnable {
    private Socket sock;
    private ServerConnect sc;
    private ObjectOutputStream oos;
    private ObjectInputStream ois;
    private boolean running=true;
    private List<String> lstr;
    public CoreServer(Socket sock, ServerConnect sc) {
        this.sock=sock;
        this.sc=sc;
    }

    @Override
    public void run() {
        lstr=new LinkedList<String>();
        try {
            oos= new ObjectOutputStream(sock.getOutputStream());
            ois=new ObjectInputStream(sock.getInputStream());


        } catch (IOException e) {
            e.printStackTrace();
        }
        while (running){
            Object o=null;
            try {
                o= ois.readObject();

            } catch (ClassNotFoundException | IOException e) {
                // TODO Auto-generated catch block
                sc.remove(this);
                stop();
            }
            if (Integer.class.isInstance(o)){
                try {
                    int num= (Integer) o;
                    if(num==0){
                        sendMsg();
                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

            else if (String.class.isInstance(o)){
                System.out.println("String Received");
                String ss= (String) o;
                sc.readyToSend(ss);

            }


        }
    }



    public void sendMsg() throws IOException{
        try {
            System.out.println("I'm going to send: "+lstr);
            oos.writeObject((Object)lstr);
            oos.flush();
            lstr.clear();
            // If I replace lstr.clear() with "lstr=new LinkedList();" it works as it should.


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

    public void addMsg(String text){
        System.out.println("I will add -"+text+"- to the list");
            lstr.add(text);

    }



}

КЛИЕНТ:

public class ClientConnect implements Runnable {
    private Socket sock;
    private boolean running=true;
    private ObjectInputStream ois;
    private ObjectOutputStream oos;
    private boolean first=true;
    private Object o;
    private ClientFrame cf;

    public ClientConnect(Socket sock, ClientFrame cf){
        this.sock=sock;
        this.cf=cf;
    }

    @Override
    public void run() {
        if (first){
            try {
                oos= new ObjectOutputStream(sock.getOutputStream());
                ois= new ObjectInputStream(sock.getInputStream());
                first=false;

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        while (running){
            try {
                oos.writeObject(new Integer(0));
                oos.flush();
            } catch (IOException e) {
                JOptionPane.showMessageDialog(null, "Connection error");
                this.stop();
                System.exit(1);
            }

            try {
                o=ois.readObject();
                System.out.println("I received o : "+(List)o);
            } catch (ClassNotFoundException | IOException e) {

                JOptionPane.showMessageDialog(null, "Server offline");
                System.exit(1);
            }

                if(List.class.isInstance(o)){
                    List<String> l=null;
                    l=(List<String>) o;
                    Iterator<String> it= l.iterator();
                    while (it.hasNext()){
                        String s=it.next();
                        System.out.println("Adding:"+s);
                        cf.history.append(s+ "\n"); //this function will show the received content on a JTextArea
                }
            }





            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    public void send(String text){
        if (!text.equals("")){
            try {
                oos.writeObject(text);
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }


        }


    }


}

Клиент должен отправить что-то, что я написал, на сервер, который затем отправит одно и то же сообщение каждому подключенному клиенту. Вот что происходит на стороне сервера и на стороне клиента, когда я что-то пишу:

Журнал сервера:

Waiting client
Found one client
Waiting client //The Server is multithreaded and is waiting for another client to connect
Waiting client
I'm going to send: []
I'm going to send: []
I'm going to send: []
String Received
I will add -Hello- to the list
I'm going to send: [Hello]
I'm going to send: []
I'm going to send: []
I'm going to send: []
String Received
I will add -Stackoverflow- to the list
I'm going to send: [Stackoverflow]
I'm going to send: []
I'm going to send: []
I'm going to send: []
I'm going to send: []

Журнал клиента:

I received o : []
I received o : []
I received o : []
You wrote: Hello
I received o : []   <-- it can't read the list that the server sent to me.
I received o : []
I received o : []
I received o : []  
You wrote: Stackoverflow
I received o : []  <-- it can't read the list that the server sent to me.
I received o : []
I received o : []
I received o : []
I received o : []

Если я заменю lstr.clear() в sendMsg() на "lstr=new LinkedList();" он работает как надо, но я не знаю, почему :(

Журнал клиента (после исправления):

 I received o : []
 I received o : []
 I received o : []
 You wrote: Hello
 I received o : [Hello]
 Adding:Hello
 I received o : []
 I received o : []
 I received o : []  
 You wrote: Stackoverflow
 I received o : [StackOverflow]
 Adding:StackOverflow
 I received o : []
 I received o : []
 I received o : []
 I received o : []

Как объяснить такое поведение?


person Leonardo Sarra    schedule 31.01.2017    source источник
comment
Вызывая lstr.clear(), вы удаляете текущее содержимое объекта. Вызов lstr = new... заставляет lstr указывать на другой объект, но не удаляет текущее содержимое объекта.   -  person Egl    schedule 31.01.2017


Ответы (1)


Протокол сериализации сохраняет идентичность объекта.

Если вы неоднократно записываете один и тот же объект, он не будет снова сериализован со своим содержимым, поток просто будет включать обратную ссылку, чтобы указать, что вы написали тот же объект в другой раз.

В результате поток будет содержать только то состояние вашего списка, которое вы отправили в первый раз, то есть пустое.

Когда вы позже добавите что-то в список и напишете список снова, это не будет подхвачено. Поток будет просто содержать метку с надписью «снова этот список».

Когда вы переходите с list.clear() на создание полностью нового экземпляра списка, вы исправляете это: теперь каждый список записывается в поток со своими данными во время записи.

person Thilo    schedule 31.01.2017