2017-01-31 20 views
0

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

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

SERVER:

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(); 
      } 


     } 


    } 


} 

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

Server Log:

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: [] 

Client Log:

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();" он работает как надо, но я не знаю, почему :(

Client Log (после исправления):

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 : [] 

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

+1

Вызов lstr.clear(), вы удаляете содержимое объекта с личными объектами. Вызов lstr = new ... заставляет lstr указывать на другой объект, но не удаляет содержимое текущего объекта – Egl

ответ

4

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

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

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

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

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