小编典典

使用Swing GUI的简单客户端-服务器程序

java

我做一个简单的, 没有线程 客户端 - 服务器 进行GUI有两个一个按钮程序 服务器客户 端。当 客户端
按下按钮时,它将按钮上的文本更改为 “ C” 并发送到 服务器 “ C” 字符串,因此 服务器 端的按钮将文本更改为
C”
服务器的 工作方式与 客户端 相似,但是发送的是 “ S” 而不是 “ C” 。他们轮流工作:轮到 客户时
服务器 客户端 始终首先启动。

客户 机按钮,它工作正常,但是当 服务器 按下按钮,它改变了按钮, “S”服务器 端而不是在 客户 端。我知道我做错了。

服务器代码:

public class Serv implements ActionListener
{
    private JButton button;
    private boolean myTurn;
    private ServerSocket sock;
    private Socket s;
    private BufferedReader input;
    private PrintStream output;

    public Serv() throws UnknownHostException, IOException
    {
        button = new JButton();
        myTurn = false;
        sock = new ServerSocket(9001);
        s = null;
        button = new JButton();
    }

    public void createGUI()
    {
        JFrame frame = new JFrame("TicTacToe - Server");
        JPanel mainPanel = new JPanel();
        mainPanel.setPreferredSize(new Dimension(100, 100));
        button = new JButton("");
        button.setPreferredSize(new Dimension(100, 100));
        button.setFont(new Font(button.getFont().getName(), button.getFont().getStyle(), 70));
        button.setActionCommand("1");
        button.addActionListener(this);
        mainPanel.add(button);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public void startMyGame() throws IOException
    {
        createGUI();
        s = sock.accept();
        input = new BufferedReader(new InputStreamReader(s.getInputStream()));
        output = new PrintStream(s.getOutputStream(), true);
        while(true)
        {
            if(myTurn == false)
            {
                myTurn = true;
                String out = input.readLine();
                button.setText(out);
            }
        }
    }

    public static void main(String args[]) 
    {
        Serv tc = null;
        try
        {
            tc = new Serv();
            tc.startMyGame();

        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            try
            {
                tc.close();
            }
            catch(Exception ex)
            {
                ex.printStackTrace();
            }
        }

    }

    private void close() throws IOException
    {
        this.sock.close();
        this.input.close();
        this.output.close();
    }

    @Override
    public void actionPerformed(ActionEvent e) 
    {
        if(myTurn == true)
        {
            if(e.getActionCommand().equals("1"))
            {
                JButton b = (JButton) e.getSource();
                b.setText("S");
                output.println("S");
                myTurn = false;
            }
        }
    }
}

客户代码:

public class Cli implements ActionListener
{
    private JButton button;
    private boolean myTurn;
    private Socket sock;
    private BufferedReader input;
    private PrintStream output;

    public Cli() throws UnknownHostException, IOException
    {
        button = new JButton();
        myTurn = true;
        sock = new Socket("127.0.0.1", 9001);
        input = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        output = new PrintStream(sock.getOutputStream(), true);
    }

    public void createGUI()
    {
        JFrame frame = new JFrame("TicTacToe - Client");
        JPanel mainPanel = new JPanel();
        mainPanel.setPreferredSize(new Dimension(100, 100));
        button = new JButton("");
        button.setPreferredSize(new Dimension(100, 100));
        button.setFont(new Font(button.getFont().getName(), button.getFont().getStyle(), 70));
        button.setActionCommand("1");
        button.addActionListener(this);
        mainPanel.add(button);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public void startMyGame() throws IOException
    {
        createGUI();
        while(true)
        {
            if(myTurn == false)
            {
                myTurn = true;
                String out = input.readLine();
                button.setText(out);
            }
        }
    }

    private void close() throws IOException
    {
        this.sock.close();
        this.input.close();
        this.output.close();
    }

    public static void main(String args[]) 
    {
        Cli tc = null;
        try
        {
            tc = new Cli();
            tc.startMyGame();

        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            try
            {
                tc.close();
            }
            catch(Exception ex)
            {
                ex.printStackTrace();
            }
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) 
    {
        if(myTurn == true)
        {
            if(e.getActionCommand().equals("1"))
            {
                JButton b = (JButton) e.getSource();
                if(!b.getText().equals("X") || !b.getText().equals("O"))
                {
                    b.setText("C");
                    output.println("C");
                    myTurn = false;
                }
            }
        }
    }
}

我已删除导入,因此代码会更短。


阅读 389

收藏
2020-11-30

共1个答案

小编典典

您的代码当前存在的问题:

  • 你正在创建一个Swing GUI的并运行它 关闭 Swing事件分派线程或EDT的。GUI应该在事件线程 启动 以便确保所有Swing代码都可以在单个线程上运行。
  • 您有一个长时间运行的while循环,它正在进行Swing突变调用,从而更新了JButton的状态。如果此代码在Swing事件线程上运行,它将阻止/冻结GUI。应该在不是EDT的后台线程中显式调用此块,并且应按照“ Swing:并发”教程中的内容,将所有Swing调用排队到事件线程
  • 您在不同的线程中使用了一个非易失性布尔值,可能会导致变量在应更改时未被更改
  • 您似乎立即关闭了流,从而阻止了关注点之间的充分沟通。

正在研究更干净的示例…

例如:

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