繁体   English   中英

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

[英]Simple Client-Server program using Swing GUI

我做一个简单的,没有线程客户端-在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;
                }
            }
        }
    }
}

我已经删除了导入,所以代码会更短。

您的代码的当前问题:

  • 你正在创建一个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();
    }    
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM