2011-09-06 27 views
1

您好我正在一個客戶端服務器程序與包含一些特殊功能,如發送私人消息,顯示在線列表等,所以我知道我必須使用序列化和第一我管理它,但過了一段時間擰了現在我花時間學習序列化。我將只分享有意義的部分以防止共同性。我想知道我犯錯的地方。無論如何感謝您的幫助。這裏是服務器代碼的一部分;java客戶端服務器序列化問題

public class Server { 

     private ServerSocket ss; 
     private Socket socket; 
     private Map<Socket,DataOutputStream> list = new HashMap<Socket,DataOutputStream>(); 
     private LinkedList<Person> client_list = new LinkedList<Person>(); 
     private String socketName; 
     private Object lockObj = new Object(); 

     public Server(int port_number) throws IOException{ 

      create_Server(port_number); 
     } 

     public static void main(String[] args) throws IOException { 

      int port_number=23; 

      new Server(port_number); 
     } 

     private void create_Server(int port_number) throws IOException{ 

      ss = new ServerSocket(port_number); 

      System.out.println("Server is ready!"); 

      while(true){ 

       socket=ss.accept(); 

       System.out.println(socket.getLocalAddress().getHostName() + " was connected!"); 

       send_con_mes(); 

       list.put(socket,new DataOutputStream(socket.getOutputStream())); 

       ServerThread st = new ServerThread(socket,this); 

       Person per = new Person(socket.getInetAddress().toString()); 

       client_list.add(per); 

       st.start(); 


      } 

     } 

      public LinkedList<Person> send_list(){ 

        return client_list; 
     } 

所以我創建服務器並等待任何套接字的響應。此外,我使用列表保存套接字和它的輸出和clien_list保存對象人(人是一個可序列化的對象)。

這裏是serverthread部分

public class ServerThread extends Thread { 

    private Socket s; 
    private Server srv; 
    private String socketName; 
    private StringTokenizer str; 
    private String message = ""; 
    private LinkedList<Person> client_list; 
    private ObjectOutputStream oos; 

    private static int i=0; 

    public ServerThread(Socket s,Server srv){ 
     this.s = s; 
     this.srv = srv; 

     try { 
      oos = new ObjectOutputStream(s.getOutputStream()); 

     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    public void setList(){ 

     client_list = srv.send_list(); 

    } 

    private LinkedList<Person> getList(){ 

     return client_list; 
    } 

    @Override 
    public void run() { 

     String msg; 
     String token; 
     DataInputStream dis; 

     try { 
      dis = new DataInputStream(s.getInputStream()); 

      while(true){ 

       msg = dis.readUTF(); 
       srv.send_to_All(msg, s); 

       setList(); 

       oos.writeObject(getList()); 
       oos.flush(); 

      } 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     finally{ 
      try { 
       srv.remove_Connection(s); 

      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 

} 

,所以我送client_list在上ObjectOutputStream oos給客戶。

終於在這裏是客戶端部分這需要列表和反序列化Person對象和讀取信息...

public class Client extends javax.swing.JFrame implements Runnable { 

    private DataOutputStream dos; 
    private DataInputStream dis; 
    private Socket s; 
    private String Client_name; 
    private String Ip_addr; 
    private Font font = new Font("Arial", Font.PLAIN, 13); 
    private int click_num_b=0; 
    private int click_num_i=0; 
    private LinkedList<Person> client_list; 

    private FileOutputStream fos; 
    private PrintStream pts; 
    private ObjectInputStream socketIn; 

/** Creates new form Client */ 
public Client() { 
    initComponents(); 
    Screen.setEditable(false); 

    Text_Field.setFont(font); 
    Screen.setFont(font); 
    start_Chat(); 

} 

    @Override 
    public void run() { 

     try { 

      while(true){ 

        read_list(); 

       String message = dis.readUTF(); 
       Screen.append(message + "\n"); 

      } 

     } catch (IOException ex) { 
      Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex); 
     } 

    } 


    private void read_list() throws IOException{ 

     socketIn = new ObjectInputStream(s.getInputStream()); 

     try { 

      client_list = (LinkedList<Person>) socketIn.readObject(); 

      for (Iterator<Person> itr = client_list.iterator(); itr.hasNext();) { 

       Person per = itr.next(); 

       pts.println(per.getnickName()); 

      } 

      socketIn.close(); 
     } catch (ClassNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    public void start_Chat() { 
     try { 

      Ip_addr = JOptionPane.showInputDialog("Enter the IP number of the server to connect : "); 
      s = new Socket(Ip_addr, 23); 

      Client_name = JOptionPane.showInputDialog("Enter your Nickname : "); 

      dis = new DataInputStream(s.getInputStream());   
      dos = new DataOutputStream(s.getOutputStream()); 

      fos = new FileOutputStream("personList.txt"); 
      pts = new PrintStream(fos); 

      new Thread(Client.this).start(); 
在這裏

私人ObjectInputStream socketIn;需要的序列化對象,並在文件上寫道。這裏是我面臨的一些錯誤

java.io.EOFException 
    at java.io.DataInputStream.readUnsignedShort(Unknown Source) 
    at java.io.DataInputStream.readUTF(Unknown Source) 
    at java.io.DataInputStream.readUTF(Unknown Source) 
    at ServerThread.run(ServerThread.java:58) 


SEVERE: null 
java.io.StreamCorruptedException: invalid type code: 00 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.readObject(Unknown Source) 
    at Client.read_list(Client.java:81) 
    at Client.run(Client.java:61) 
    at java.lang.Thread.run(Unknown Source) 

所以我很感激,如果你能幫我處理這個問題。

+0

將套接字聲明爲類變量並僅將其用作方法的本地變量有點難以理解。 – corsiKa

+0

好吧,我會很高興,如果你能更清楚地解釋你的想法:) – quartaela

+0

當然。我將'套接字套接字'移動到'create_Server'中的'while'循環中。這將防止任何東西與套接字對象混淆,並更可靠地保護套接字對象。你永遠不想公開信息不必要的。 – corsiKa

回答

1

只發送過自己的對象。例如,

interface ServerToClientPacket { 
    void performAction(Client c); 
} 

class MyMessage implements ServerToClientPacket { 
    String message; 
    MyMessage(String message) { this.message = message; } 
    void performAction(Client c) { 
     JOptionPane.showMessageDialog(message); 
    } 
} 

class PersonList implements ServerToClientPacket { 
    LinkedList<Person> people; 
    // constructor here 
    void performAction(Client c) { 
     for(Person person : people) { 
      c.pts.println(person); 
     } 
    } 
} 

每個將在客戶端實現自己的performAction與序列化的數據。定義行爲時,不要將其放入客戶端,而要將其放入消息中。然後你的客戶端變成了從套接字傳遞給它的各種消息和行爲的顯示機制。

+0

好的這種方式更容易理解和使用簡單。我會嘗試這個想法,並在我的工作上再次設計。所以感謝您的幫助隊友:) – quartaela

1

看起來您正在使用流和相同流的裝飾版本。因爲有一些緩衝正在進行,這不會奏效。堅持只使用一個裝飾實例。

+0

那麼如何使用一個裝飾流,它攜帶的消息和對象_ ?.我怎麼能意識到傳入的數據是一個對象或消息。 – quartaela

+0

@ user743989爲什麼不讓通過流的消息對象呢?只接受對象,不管它們是消息對象還是行爲對象或任何東西。 – corsiKa

+0

好吧,我如何才能實現對象類型。例如,如果它是一個字符串對象或一個'Person'對象,或者它可能是一個包含對象'Person'_?的LinkedList。並抱歉,這些煩惱的問題,但我也是新的Java :) – quartaela

0

你假設你'必須使用序列化'。序列化當然是一種選擇,但當然不是唯一的選擇。

序列化有幾個缺點:

  • Java的具體
  • 複雜 - 序列化是Java語言的更高級的功能之一
  • 棘手的重構(如果你不能總是同時升級客戶端和服務器同時進行,因此對串行化的類進行更改可能會非常棘手)
  • 難以調試(如果出現問題,您無法手動檢查「線路上發生了什麼」並查看是否正確)

使用另一種爲客戶端 - 服務器通信設計的編碼(想到JSON)可能值得考慮。(我知道這很煩人,當你問一個問題「我如何用X做事」,人們回答「不要使用X,使用Y!」,但似乎你可能想要考慮這一點...)

+0

是的,你是對的,但我想使用序列化因爲我想更清楚地學習這個問題,我告訴我,我也是新的網絡的Java。另外隊友不會讓我煩惱:)。另一方面,我試圖完成這項工作只與簡單的Java:D所以試圖學習JSON將強迫我:)。但無論如何感謝您的建議 – quartaela