Simple Client-Server program using Swing GUI

后端 未结 1 828
余生分开走
余生分开走 2021-01-28 22:01

I\'m making a simple, no thread Client-Server program where GUI has one button on both server and client side. When clie

相关标签:
1条回答
  • 2021-01-28 22:25

    Current issues with your code:

    • You're creating a Swing GUI and running it off of the Swing event dispatch thread or EDT. GUI's should be started on the event thread so that all Swing code is guaranteed to run on a single thread.
    • You've got a long-running while loop, and it is making Swing mutational calls, updating the state of a JButton. If this code were running on the Swing event thread, it would block/freeze the GUI. This block should be explicitly called in a background thread that is not the EDT, and all Swing calls should be queued onto the event thread as per the Lesson: Concurrency in Swing tutorial.
    • You're using a non-volatile boolean in different threads, risking the variable not being changed when it should be changed
    • You appear to be closing your streams immediately, preventing adequate communication between concerns.

    Working on a cleaner example.......

    For example:

    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import java.io.IOException;
    import java.io.PrintStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Scanner;
    
    import javax.swing.*;
    
    public class SimpleServerClient {
        private static final int PORT = 9001;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                try {
                    SimpleServer server = new SimpleServer(PORT, "Server", false);
                    SimpleClient client = new SimpleClient(PORT, "Client", true);
                    server.createGui();
                    client.createGui();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }
    

    interface SimpleGui {
        void sendLine(String nextLine);
    }
    

    // background thread handles listening to the Scanner 
    // which scans a Socket's InputStream
    class MyWorker extends SwingWorker<Void, Void> {
        public static final String LINE = "line";
        private Scanner inputScanner;
        private SimpleGui gui;
        private String line = "";
    
        public MyWorker(Scanner inputScanner, SimpleGui gui) {
            this.inputScanner = inputScanner;
            this.gui = gui;
        }
    
        @Override
        protected Void doInBackground() throws Exception {
            while (inputScanner.hasNext()) {
                // get line from Scanner                
                // use the setter method in case we want to use a PropertyChangeListener later
                setLine(inputScanner.nextLine());
    
                // send line to the GUI
                gui.sendLine(getLine());
            }
            return null;
        }
    
        public String getLine() {
            return line;
        }
    
        // again rigged up to allow use of PropertyChangeListeners
        public void setLine(String line) {
            this.line = line;
            firePropertyChange(LINE, null, line);
        }
    }
    

    // code that both the client and server GUI classes share
    abstract class DefaultGui implements SimpleGui {
    
        // this guy ***must**** be volitile!
        private volatile boolean myTurn;
        protected Scanner inputScanner;
        protected PrintStream out;
        protected JButton button = new JButton("Blank");
        protected Socket socket;
        protected String name;
        protected int port;
    
        public DefaultGui(int port, String name, boolean myTurn) {
            this.port = port;
            this.name = name;
            this.myTurn = myTurn;
        }
    
        @Override
        public void sendLine(String nextLine) {
            button.setText(nextLine);
            myTurn = true;
        }
    
        public void createGui() {
            button.addActionListener(e -> actionPerformed(e));
            JPanel panel = new JPanel();
            panel.setPreferredSize(new Dimension(300, 300));
            panel.add(button);
    
            JFrame frame = new JFrame(getName());
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(panel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        protected void actionPerformed(ActionEvent e) {
            if (!myTurn) {
                return;
            }
            out.println(getName());
            button.setText(getName());
            myTurn = false;
        }
    
        public String getName() {
            return name;
        }
    
    }
    

    class SimpleServer extends DefaultGui {
        private ServerSocket serverSocket;
    
        public SimpleServer(int port, String name, boolean myTurn) throws IOException {
            super(port, name, myTurn);
            serverSocket = new ServerSocket(port);
            new Thread(() -> {
                try {
                    // accept() blocks the current thread, so must be called on a background thread
                    socket = serverSocket.accept();
                    inputScanner = new Scanner(socket.getInputStream());
                    out = new PrintStream(socket.getOutputStream(), true);
                    new MyWorker(inputScanner, this).execute();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }    
    }
    

    class SimpleClient extends DefaultGui {
    
        public SimpleClient(int port, String name, boolean myTurn) throws IOException {
            super(port, name, myTurn);
            socket = new Socket("localhost", port);
            inputScanner = new Scanner(socket.getInputStream());
            out = new PrintStream(socket.getOutputStream());
            new MyWorker(inputScanner, this).execute();
        }    
    }
    
    0 讨论(0)
提交回复
热议问题