2011-01-10 7 views
2

Ich habe ein einfaches Server - Client-Programm mit Swing-Schnittstelle mit Singleton und Beobachter Muster geschrieben. Jeder Client stellt eine Verbindung zum Server her und kann Nachrichten senden. Der Server leitet die empfangenen Nachrichten an die übrigen Clients weiter. Die Clients verwenden eine grafische Benutzeroberfläche, mit der sie sich jederzeit mit dem Server verbinden und trennen können. Das Programm funktioniert ziemlich gut, weil ich versuche - überall fangen, die jede Ausnahme behandeln, die auftreten kann. Aber wenn Sie damit spielen, werden Sie in der Konsole eine Million von Ausnahmen sehen. Das liegt wahrscheinlich an schlechtem Design, aber ich habe mein Bestes versucht, einen sauberen Code zu schreiben. so ist die Frage:Refactoring-gute Praxis in Sockets-einfache Server-Client Swing appl

Kann jemand mir geben Hinweise und berät, wie Sie den Code Refactoring mehr richtig und sauber zu sein (vor allem, wenn es einen Client vom Server trennen kommt)?

Es gibt eine Hauptmethode in der Klasse CustomServer zum Starten des Servers und eine Hauptmethode im Controller, um den Client (mit GUI) zu starten.

Vielen Dank für Ihre freundliche Hilfe! Hier

ist der Code:

CustomServer Klasse

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

} 

Custom Klasse

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 Klasse

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

Controller-Klasse

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

und GUI-Klasse

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. Das ist eine Menge Code, von dem man erwartet, dass die Leute lesen, mit ihm spielen, Verbesserungen vorschlagen ... Unzusammenhängend Randbemerkung: Es gibt ein Refactor-My-Code-Tag? Das bringt mich zum Weinen. –

+0

ich denke, du hast Recht, es war ein langer Schuss. Aber zu meiner Verteidigung scheint der Code größer zu sein, weil ich MVC und Beobachtermuster verwende! – Pitelk

+0

Wir können versuchen, http://codereview.stackexchange.com/, aber Sie müssten Schwerpunkte oder sogar teilen diese in mehrere Fragen zu realistisch erwarten gutes Feedback. – TryPyPy

Antwort

2

Ohne Code gründlich zu untersuchen, sehe ich kein Problem mit diesem Ansatz, um die observer pattern umzusetzen. MVCGame ist ein verwandtes Beispiel. Die Synchronisation bleibt eine potentielle Falle: Kudos für den Start auf der event dispatch thread, aber bedenken Sie, dass append() in Java 7 nicht mehr Thread-sicher ist. Dieses Beispiel zeigt eine Alternative, die auch invokeLater() verwendet.

+0

Danke für die nützlichen Links! – Pitelk