2011-09-06 3 views
1

привет, я работаю над клиентской серверной программой, содержащей некоторые специальные функции, такие как отправка личного сообщения, отображение онлайн-списка и т. Д., Поэтому я знаю, что должен использовать сериализацию, и сначала я ее управлял, но через некоторое время up :) В настоящее время я провожу время, чтобы научиться сериализовать. я буду использовать только значимые части для предотвращения comlpexity. и я хочу узнать, где я делаю неправильно. так что спасибо за вашу помощь. вот часть кода сервера;проблема сериализации сервера клиентских серверов 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 сохраняет объект Object (человек является сериализуемым объектом).

здесь 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 клиентам.

наконец, здесь есть клиентская часть, которая принимает список и десериализации лица объекта и прочитать информацию ...

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

Немного уродливо объявить 'socket' как переменную класса и использовать его только как переменную, локальную для метода. – corsiKa

+0

хорошо, я буду рад, если вы сможете более четко объяснить свою идею :) – quartaela

+0

Конечно. Я бы переместил 'Socket socket' в цикл' while' в 'create_Server'. Это предотвратит что-либо из когда-либо возится с объектом сокета и, более точно, защитит его. Вы никогда не хотите, чтобы информация была излишне. – 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); 
     } 
    } 
} 

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

+0

ok этот способ более понятен и прост в использовании. я попробую эту идею и снова займусь своей работой. так спасибо за помощь помощник :) – quartaela

1

Похоже, вы используете поток и оформленную версию того же потока. Поскольку происходит буферизация, это не сработает. Придерживайтесь использования только одного украшенного экземпляра.

+0

Хорошо, тогда как можно использовать один декорированный поток, который несет сообщения и объекты _ ?. и как я могу понять, что входящие данные являются объектом или сообщением ._? – quartaela

+0

@ user743989 Почему бы вам не создавать объекты сообщений, которые попадают в поток? Только когда-либо принимайте объекты, будь то объекты сообщений или объекты поведения или что-то еще. – corsiKa

+0

ОК, так как я могу реализовать тип объектов. например, если это строковый объект или объект Person или он может быть Linkedlist, который содержит объекты 'Person'_ ?. и извините за эти неприятные вопросы, но я также новичок в java :) – quartaela

0

Вы предполагаете, что вы должны использовать сериализацию '. Сериализация, конечно, является вариантом здесь, но, конечно, не единственным вариантом.

Сериализация имеет несколько недостатков:

  • Java-специфический
  • Complicated - Сериализация одна из наиболее продвинутых особенностей языка Java
  • Tricky реорганизовать (если вы не можете всегда обновлять и клиент и сервер одновременно, внесение изменений в классы, которые также сериализованы, могут быть сложными)
  • Трудно отлаживать (если есть проблема, вы не можете вручную проверить, что происходит «по кабелю» и посмотреть, правильно ли это)

Использование другой кодировки, предназначенной для взаимодействия клиент-сервер (JSON), стоит рассмотреть.

(Я знаю, что это раздражает, когда вы задаете вопрос «как мне сделать foo с X», и люди отвечают «не используйте X, используйте Y!», Но похоже, что вы можете подумать об этом ...)

+0

да, вы правы, но я хочу использовать сериализацию, потому что я хочу более четко изучить эту тему, и я сказал, что я тоже новичок в сети Java. Кроме того, я не буду раздражать меня :). с другой стороны, я пытаюсь закончить эту работу только с простой java: D, поэтому попытка обучения JSON будет компульсивна для меня :). но в любом случае спасибо за ваше предложение – quartaela