2011-01-10 1 views
2

J'ai écrit un simple programme serveur - client avec l'interface Swing en utilisant le modèle singleton et observateur. Chaque client se connecte au serveur et peut envoyer des messages. Le serveur transmet les messages qu'il reçoit aux autres clients. Les clients utilisent une interface graphique qui leur permet de se connecter et de se déconnecter au serveur à tout moment. Le programme fonctionne plutôt bien parce que j'ai essayé partout où il y a des exceptions qui peuvent survenir. Mais si vous jouez avec, vous verrez dans la console un million d'exceptions. C'est probablement à cause d'un mauvais design mais j'ai fait de mon mieux pour faire un code propre. donc la question est:Refactoring - bonne pratique dans Sockets-simple serveur-client Swing appl

Quelqu'un peut-il me donner des conseils et des conseils sur la façon de refactoriser le code pour être plus correct et plus propre (surtout quand il s'agit de déconnecter un client du serveur)?

Il existe une méthode principale dans la classe CustomServer pour démarrer le serveur et une méthode principale dans le contrôleur pour démarrer le client (avec GUI).

Nous vous remercions de votre aide!

Voici le code:

classe CustomServer

package model; 
import java.io.*; 
import java.net.*; 
import controller.Controller; 


public class CustomServer extends Thread{ 
private ServerSocket ss = null;; 



public CustomServer() throws Exception { 
    ss = new ServerSocket(4444); 
    this.start(); 
} 

@Override 
public void run(){ 
    while (true){ 
     try { 
      Socket connSoc = ss.accept(); 
      new Connect(connSoc); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      try{ 
       ss.close(); 
      }catch (Exception e1) { 
       e1.printStackTrace(); 
      } 
     } 

    } 
} 

private class Connect extends Thread{ 
    ObjectOutputStream out; 
    ObjectInputStream in; 

    public Connect(Socket connSoc) { 
     final IOController server = IOController.getInstance(); 
     try { 
      out = new ObjectOutputStream(connSoc.getOutputStream()); 
      in = new ObjectInputStream(connSoc.getInputStream()); 
      server.add(in, out); 
     }catch (Exception e) { 
      e.printStackTrace(); 
      try{ 
       connSoc.close(); 
      }catch (Exception ex) { 
       e.printStackTrace(); 
      } 
     } 
     this.start(); 
    } 
} 



public static void main(String[] args) throws Exception{ 
    new CustomServer(); 
} 

} 

CustomClient Classe

package model; 
import java.io.*; 
import java.net.*; 
import java.util.*; 

public class CustomClient extends Observable{ 

private Socket connSocket; 
private ObjectOutputStream out; 
private ObjectInputStream in; 
private boolean isOn = true; 
private Thread receiver; 

public CustomClient() throws Exception{ 
     System.out.println("inside CClient"); 
     Socket soc = new Socket(); 
     soc.connect(new InetSocketAddress(InetAddress.getLocalHost(), 4444)); 
     out = new ObjectOutputStream(soc.getOutputStream()); 
     in = new ObjectInputStream(soc.getInputStream()); 
} 

public void transmit(Object obj){ 
    System.out.println("CClient - transitmin - start"); 
    try { 
     out.writeObject(obj); 
     out.flush(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    System.out.println("CClient - transitmin - end"); 
} 

public void reveive(){ 
    System.out.println("CClient - recieve - start"); 
    receiver = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      while (isOn){ 
       Object obj = null; 
       try { 
        obj = in.readObject(); 
        setChanged(); 
       } catch (Exception ex){ 
        ex.printStackTrace(); 

       } 
       if (hasChanged()){ 
        notifyObservers(obj); 
       } 
      } 

     } 
    }); 
    receiver.start(); 
    System.out.println("CClient - recieve - end"); 

} 

public void closeConnection(){ 
    try{ 
     in.close(); 
    } catch (Exception e) { 
     System.err.println("CAUGHT"); 
     e.printStackTrace(); 
    } 
    try{ 
     out.close(); 
    } catch (Exception e) { 
     System.err.println("CAUGHT"); 
     e.printStackTrace(); 
    } 
    finally { 
     try { 
      isOn = false; 
      in = null; 
      out = null; 
      connSocket.close(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     connSocket = null; 
    } 
} 

public Socket getSocket(){ 
    return connSocket; 
} 

} 

IOController classe

package model; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.util.ArrayList; 

public class IOController{ 

ArrayList<ObjectInputStream> ins = new ArrayList<ObjectInputStream>(); 
ArrayList<ObjectOutputStream> outs = new ArrayList<ObjectOutputStream>(); 
private static IOController instance = new IOController(); 

private IOController() {  
} 

public static IOController getInstance(){ 
    return instance; 
} 

public void add(final ObjectInputStream in, final ObjectOutputStream out){ 
    ins.add(in); 
    outs.add(out); 
    new Connect(in); 
} 

private class Connect extends Thread{ 
    ObjectInputStream in; 

    public Connect(ObjectInputStream in) { 
     this.in = in; 
     this.start(); 
    } 

    @Override 
    public void run() { 
     boolean isOn = true; 
     ArrayList<ObjectOutputStream> toBeRemoved = new ArrayList<ObjectOutputStream>(); 
     while(isOn){ 
      try { 
       Object obj = in.readObject(); 
       for (ObjectOutputStream out : outs){ 
        try { 
         out.writeObject(obj); 
         out.flush(); 
        }catch (Exception ex){ 
         toBeRemoved.add(out); 
         ex.printStackTrace(); 
        } 
       } 
       for (ObjectOutputStream oos : toBeRemoved){ 
        outs.remove(oos); 
       } 
      }catch (Exception ex){ 
       ins.remove(in); 
       isOn = false; 
       in = null; 
       ex.printStackTrace(); 
      } 
     } 
    } 
} 
} 

classe contrôleur

package controller; 
import java.awt.*; 
import view.GUI; 
import model.CustomClient; 

public class Controller { 

private GUI gui; 
private CustomClient client; 


public Controller() { 
    gui = new GUI(); 
    gui.addConnectButtonActionListener(new ConnectButtonActionListener()); 
    gui.addTextFieldKeyListner(new TextFieldKeyListener()); 
    gui.addDisconnectButtonActionListener(new DisconnectButtonActionListener()); 
    gui.addCustomWindowListener(new GuiWindowListener()); 
} 

private class DisconnectButtonActionListener implements ActionListener{ 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     client.closeConnection(); 
     client = null; 
     gui.getDisconnectButton().setEnabled(false); 
     gui.getConnectButton().setEnabled(true); 
    } 
} 


private class ConnectButtonActionListener implements ActionListener{ 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     try { 
      client = new CustomClient(); 
      client.addObserver(gui); 
      client.reveive(); 
      gui.getConnectButton().setEnabled(false); 
      gui.getDisconnectButton().setEnabled(true); 
     }catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 
} 

private class TextFieldKeyListener extends KeyAdapter{ 

    @Override 
    public void keyReleased(KeyEvent e) { 
     if (e.getKeyCode()==KeyEvent.VK_ENTER){ 
      String msg = gui.getTextField().getText(); 
      gui.getTextField().setText(""); 
      if (client != null){ 
       client.transmit(msg); 
      } 
     } 
    } 
} 

private class GuiWindowListener extends WindowAdapter{ 

    @Override 
    public void windowClosing(WindowEvent e) { 
     try{ 
      if (client != null){ 
       client.closeConnection(); 
       client = null; 
      } 
     }catch (Exception e2) { 

     } 
     System.out.println("closed"); 


    } 
} 

public static void main(String[] args) { 
    new Controller(); 
    } 
} 

et classe GUI

package view; 
import java.awt.*; 
import java.awt.event.*; 
import java.util.*; 
import javax.swing.*; 
public class GUI extends JFrame implements Observer{ 

private JTextField textField; 
private JTextArea displayArea; 
private JButton connectButton; 
private JButton disconnectButton; 

public GUI() { 
    init(); 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    SwingUtilities.invokeLater(new Runnable() { 

     @Override 
     public void run() { 
      pack(); 
      setVisible(true); 
      textField.requestFocusInWindow(); 
     } 
    }); 
} 

public void addConnectButtonActionListener(ActionListener al){ 
    connectButton.addActionListener(al); 
} 
public void addDisconnectButtonActionListener(ActionListener al){ 
    disconnectButton.addActionListener(al); 
} 
public void addTextFieldKeyListner(KeyListener kl){ 
    textField.addKeyListener(kl); 
} 

public void addCustomWindowListener(WindowListener guiWindowListener) { 
    addWindowListener(guiWindowListener); 

} 

public void appendText(String text){ 
    displayArea.append("\n"+ text); 
} 

private void init() { 
    JPanel panel = new JPanel(); 
    JPanel southPanel = new JPanel(); 
    JPanel northPanel = new JPanel(); 

    connectButton = new JButton("connect"); 
    connectButton.setFocusable(false); 
    disconnectButton = new JButton("disconnect"); 
    disconnectButton.setFocusable(false); 
    textField = new JTextField(20); 
    displayArea = new JTextArea(); 
    displayArea.setEditable(false); 
    displayArea.setPreferredSize(new Dimension(300,250)); 

    panel.setLayout(new BorderLayout()); 
    southPanel.setLayout(new FlowLayout()); 
    northPanel.setLayout(new FlowLayout()); 

    northPanel.add(displayArea); 
    southPanel.add(connectButton); 
    southPanel.add(disconnectButton); 

    panel.add(textField,BorderLayout.CENTER); 
    panel.add(southPanel, BorderLayout.SOUTH); 
    panel.add(northPanel, BorderLayout.NORTH); 
    this.getContentPane().add(panel); 

    disconnectButton.setEnabled(false); 

    System.out.println(textField.hasFocus()); 
} 


public JTextField getTextField() { 
    return textField; 
} 

public void setTextField(JTextField textField) { 
    this.textField = textField; 
} 

public JTextArea getDisplayArea() { 
    return displayArea; 
} 

public void setDisplayArea(JTextArea displayArea) { 
    this.displayArea = displayArea; 
} 

public JButton getConnectButton() { 
    return connectButton; 
} 

public void setConnectButton(JButton connectButton) { 
    this.connectButton = connectButton; 
} 

public JButton getDisconnectButton() { 
    return disconnectButton; 
} 

public void setDisconnectButton(JButton disconnectButton) { 
    this.disconnectButton = disconnectButton; 
} 

@Override 
public void update(Observable observable, Object object) { 
    displayArea.append("\n"+(String)object); 
} 
} 
+1

Hmm. C'est beaucoup de code pour s'attendre à ce que les gens lisent, jouent avec, suggèrent des améliorations sur ... Note de côté non liée: Il y a un tag 'refactor-mon-code'? Cela me fait pleurer. –

+0

Je suppose que vous avez raison, c'était un long-shot. mais pour ma défense le code semble plus grand que c'est parce que j'utilise MVC et un pattern d'observateur! – Pitelk

+0

Nous pouvons essayer à http://codereview.stackexchange.com/, mais vous devez déclarer des points focaux ou même le diviser en plusieurs questions pour obtenir de manière réaliste de bons commentaires. – TryPyPy

Répondre

2

Sans examiner votre code bien, je ne vois aucun problème avec cette approche de mise en œuvre du observer pattern. MVCGame est un exemple associé. La synchronisation reste un piège potentiel: félicitations pour commencer sur le event dispatch thread, mais attention, append() n'est plus thread-safe dans Java 7. Cet exemple montre une alternative qui utilise également invokeLater().

+0

Merci pour les liens utiles! – Pitelk