Java如何通过网络发送数据通过UI按钮

时间:2017-04-04 20:49:51

标签: java sockets multiplayer

我正在学习套接字以及服务器/客户端如何通信。

到目前为止,我的协议已经找到并设法模拟合成TCP三次握手:

  1. 客户端成功连接到服务器并发送SYN。
  2. 服务器接收SYN并将SYNACK回复给客户端。
  3. 客户端收到SYNACK,并向服务器回复ACK。
  4. 多数民众赞成,所有这些都是在新线程中我的Runnable客户端服务的while(true)循环下的Run()方法中线性执行的。我不知道GUI类中的Button如何告诉我的客户端服务发送特定数据包,例如,当服务在不同的线程中运行时,按下UI中的特定按钮。

    我有一个想法,但在此纠正我:不知何故为我的GUI中的所有按钮添加ActionListeners而不是GUI ..

    感谢。

    PS。我正在使用DataInputStream和DataOutputStream从/向套接字流读取/写入数据。

    ClientService.java:

    public class ClientService implements Runnable, GameProtocol    {
        private Socket socket;
        private int clientNumber;
        private GameClient client;
        private JTextArea clientConsole;
        private DataInputStream fromServer;
        private DataOutputStream toServer;
    
        public ClientService(Socket aSocket, GameClient aClient, JTextArea textArea)    {
            this.socket = aSocket;
            this.client = aClient;
            this.clientConsole = textArea;
        }
        private void buildStreams() throws Exception    {
            this.fromServer = new DataInputStream(this.socket.getInputStream());
            this.toServer = new DataOutputStream(this.socket.getOutputStream());
        }
        public void sendPacket(int data)    {
            try     {
                this.toServer.writeInt(data);
            }   catch   (Exception e)   {
                e.printStackTrace();
            }
            return;
        }
        public void flushPacket()   {
            try     {
                this.toServer.flush();
            }   catch   (Exception e)   {
                e.printStackTrace();
            }
            return;
        }
    
        public void run()   {
            try {
                try {
                    buildStreams();
                    toServer.writeInt(PLAYER_SYN);  // start synthetic three way handshake
                    toServer.flush();
                    if(fromServer.readInt() == SERVER_SYNACK)   {
                        this.clientNumber = fromServer.readInt();
                        clientConsole.append("Client number from Server: " + clientNumber + "\n");
                        toServer.writeInt(PLAYER_ACK);
                        toServer.writeInt(this.clientNumber);
                        toServer.flush();
                    }
                    else    {
                        clientConsole.append("Client -> Server Sync failed. Can't proceed.\n");
                        toServer.writeInt(PLAYER_QUIT);
                        toServer.flush();
                        socket.close();
                        System.exit(-1);
                    }
                    executeCommand();
                }   finally {   
                    socket.close();
                }
            }   catch (Exception e) {
                System.out.println("Client Service: " + e.getMessage());
            }
        }
        private void executeCommand() throws Exception  {
            boolean quit = false;
            while(!quit)    {
                int command = -14324;
                if(fromServer.available() > 0)  {
                    command = fromServer.readInt();
                }
                switch (command)    {
                    case WINNER:
                        clientConsole.append("You Win.\n");
                        break;
                    case LOSER:
                        clientConsole.append("You Lost.\n");
                        break;
                    case ENABLE_TURN:
                        client.enableTurn();
                        break;
                    case DISABLE_TURN:
                        client.disableTurn();
                        break;
                }
            }
        }
    }
    

    GameClient.java:

    public class GameClient extends JFrame implements GameProtocol  {
    /**
     * TextArea size.
     */
        private final int 
            TEXTAREA_ROWS = 5,
            TEXTAREA_COLS = 40;
    /**
     * Client window size, unadjustable.
     */
        private final int 
            FRAME_W = 535,
            FRAME_H = 600;  
    
        // for Assignment 10
        private Socket socket;
        private DataOutputStream toServer;          
        private DataInputStream fromServer;
    /**
     * ArrayList of type Cards, by default, holds 20 cards.
     */
        private ArrayList<Card> cards;
    /**
     * Console for debugging.
     */
        private JTextArea gameConsole;
    /**
     * Button to terminate game
     */
        private JButton quitButton;
    /**
     * Main Frame panels, cardsPanel and consolePanel are sub-panels of mainPanel.
     */
        private JPanel mainPanel, cardsPanel, consolePanel;
    /**
     * Builds packets to be sent to the server
     */
        private Packet packet;
    /**
     * players points, accumulated.
     */
        private int points = 0;
    /**
     * card choice 1
     */
        private int choice1 = -1;
    /**
     * card choice 2
     */
        private int choice2 = -1;
    /**
     * for building packet arguments
     */
        private static int packetBuilderCount = 0;
    /**
     * Counter for outbound and inbound packets
     */
        private static int packetNumber = 1;
    /**
     * for timing out cards when recieving no match
     */
        private Timer timer;
    /**
     * true when user is allowed to pick cards.
     * false when another user is true
     */
        private boolean isTurn = true;
        // service
        private ClientService service;
    /**
     * default contrustor. Builds JFrame and all components.
     */
        public static void main(String[] args)  {
            new GameClient();
        }
        public GameClient() {
            packet = new Packet();
            buildButton();
            buildCards();
            addEventToCards();      // adds actionlistener to each card.
            buildPanel();
            buildTimer();
            buildFrame();
            buildConnection();  // for assignment 10            
        }
        private void buildConnection()  {
            try {
                this.socket = new Socket(HOST, PORT);
    //          this.toServer = new DataOutputStream(socket.getOutputStream());
    //          this.fromServer = new DataInputStream(socket.getInputStream());
                gameConsole.append("Socket Connected\n");
                service = new ClientService(socket, this, this.gameConsole);
                new Thread(service).start();
    
            }   catch   (SecurityException ex)  {
                System.out.println("Check your firewall or antivirus. Unable to establish connection to server.");
            }   catch   (UnknownHostException ex)   {
                System.out.println("Host can't be found. Unable to establish connection to server.");
            }   catch   (ConnectException ex)   {
                System.out.println("Connection refused. What now?");
                ex.printStackTrace();
    //          ex.printStackTrace();
            }   catch   (IOException ex)    {
                System.out.println("fuck......");
            }
        }
    /**
     * initializes the timer.
     */
        private void buildTimer()   {
            int delay = 3000;   // wait for 3000ms
            timer = new Timer(delay, new AbstractAction() {
    /**
     * event handler for timer. Flips the cards back to face down position.
     */
                @Override
                public void actionPerformed(ActionEvent ae) {
                    flipCard(choice1, 10);      
                    flipCard(choice2, 10);
                }
            });
        }
    /**
     * Initializes JFrame
     */
        private void buildFrame()   {
            this.setSize(FRAME_W, FRAME_H);
            setResizable(false);
            this.add(mainPanel);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
        }
    /**
     * Initializes and compiles panels together. Adds Cards to panels
     */
        private void buildPanel()   {
            gameConsole = new JTextArea(TEXTAREA_ROWS, TEXTAREA_COLS);
            JScrollPane scrollConsole = new JScrollPane(gameConsole);
            scrollConsole.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_NEVER);
            gameConsole.setEditable(false);
            mainPanel = new JPanel();
            mainPanel.setPreferredSize(new Dimension(535, 475));
            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
            cardsPanel = new JPanel(new GridLayout(4, 5, 20, 20));
            for(int i = 0; i < 20; i++) {
                cardsPanel.add(this.cards.get(i));
            }
            consolePanel = new JPanel();
            consolePanel.add(scrollConsole);
            consolePanel.add(quitButton);
            mainPanel.add(cardsPanel);
            mainPanel.add(consolePanel);
        }
    /**
     * builds quit button, adds action listener to handle click
     */
        private void buildButton()  {
            quitButton = new JButton("Quit");
            quitButton.addActionListener(e -> {
                buildQuitPacket();
            });
        }
    /**
     * builds 20 Card object.
     */
        private void buildCards()   {
            cards = new ArrayList<Card>();
            Card temp;
            for(int i = 0; i < 20; i++) {
                temp = new Card();
                cards.add(temp);
            }
        }
    /**
     * adds actionlistener to all 20 card objects.
     */
        private void addEventToCards()  {
            for(int i = 0; i < 20; i++) {
                final int INDEX = i;
                cards.get(i).addActionListener(e -> buildButtonPacket(this.cards.get(INDEX).getId()));
            }
        }
    /**
     * Builds and sends a Packet when a card is chosen
     * @param value The card ID which was chosen.
     */
        private void buildButtonPacket(int value)   {
            if(!isTurn) {
                this.gameConsole.append("Its not you're turn.\n");
                return;
            }
            if(packetBuilderCount == 0) {
                packet.writeCommandToPacket(PICKED_CARDS);
                packet.writeValueToPacket(value);
                packetBuilderCount++;
                choice1 = value;
            }
            else if(packetBuilderCount == 1)    {
                packet.writeValueToPacket(value);
                packetBuilderCount = 0;
                writeToConsoleOutBound(packet.toString());
                choice2 = value;
    //          try{
    //              out.print(this.packet.getPacket());
    //              out.flush();
    //          }   catch   (Exception e)   {
    //              gameConsole.append("could not send packet.\n");
    //          }
                packet.clearPacket();
            }
        }
    /**
     * For handling commands from recieved Packet
     * @param recieved the Packet object recieved. Gets and handles command and possible arguments that follows.
     * See GameProtocol class for packet command definitions.
     */
        public void handlePacket(Packet recieved)   {
            int cmd = recieved.getCommand();
            writeToConsoleInBound(recieved.toString());
            int arg1 = -99;
            int arg2 = -99;
            switch (cmd)    {
                case SERVER_SYNACK:
                    arg1 = recieved.getFirstArg();
                    if(arg1 == 1)   {
                        this.isTurn = true;
                    }
                    else if (arg1 == 0) {
                        this.isTurn = false;
                    }
                    else    {
                        writeToConsoleError("Server sync failed. Terminating..");
                        try {
                            Thread.sleep(3000);
                        }   catch   (InterruptedException ex)   {
                            writeToConsoleError(ex.getMessage());
                        }   finally {
                            System.exit(-1);
                        }
                    }
                    break;
                case CARDMATCH:
                    arg1 = recieved.getFirstArg();
                    arg2 = recieved.getSecondArg();
                    if(arg1 > 9)    {
                        arg1 = 9;
                    }
                    if(arg2 > 9)    {
                        arg2 = 9;
                    }
                    flipCard(choice1, arg1);
                    flipCard(choice2, arg2);
                    break;
                case CARDNOMATCH:
    //              System.out.println("CLIENT: im going to sleep");
                    arg1 = recieved.getFirstArg();
                    arg2 = recieved.getSecondArg();
                    if(arg1 > 9)    {
                        arg1 = 9;
                    }
                    if(arg2 > 9)    {
                        arg2 = 9;
                    }
                    flipCard(choice1, arg1);
                    flipCard(choice2, arg2);
                    this.cardsPanel.revalidate();
                    this.cardsPanel.repaint();
                    this.consolePanel.revalidate();
                    this.consolePanel.repaint();
                    timer.setRepeats(false);    //the timer should only go off once
                    timer.start();
                    break;
                case SHOW_CARD:
                    arg1 = recieved.getFirstArg();
                    arg2 = recieved.getSecondArg();
                    if(arg1 < 0 || arg1 > 19)   {
                        writeToConsoleError(" BAD PACKET ARGUMENT 1, \nCard index out of bounds");
                    }
                    else if(arg2 < 0 || arg2 > 10)  {
                        writeToConsoleError(" BAD PACKET ARGUMENT 2, \nImage index out of bounds");
                    }
                    else    {
                        flipCard(arg1, arg2);
                    }
                    break;
                case ENABLE_TURN:
                    this.isTurn = true;
                    break;
                case DISABLE_TURN:
                    this.isTurn = false;
                    break;
                case WINNER:
                    this.gameConsole.append("You win!\n");
                    break;
                case LOSER:
                    this.gameConsole.append("You lost :( \n");
                    break;
                case ADD_POINTS:
                    arg1 = recieved.getFirstArg();
                    this.points += arg1;
                    this.gameConsole.append("** Gained " + Integer.toString(arg1) + ", you now have " + Integer.toString(this.points) + " points.\n");
                    break;
                case OTHER_QUIT:
                    this.gameConsole.append("Other player forfeited. You win!\n");
                    break;
            }
        }
    /**
     * Builds a packet containing QUIT when quit button is pressed
     * Only available when isTurn == true.
     */
        private void buildQuitPacket()  {
            if(this.isTurn == false)    {
                this.gameConsole.append("You can only quit when it is your turn.");
                return;
            }
            service.sendPacket(PLAYER_QUIT);
            service.flushPacket();
    //      this.service.sendPacket(PLAYER_QUIT);
    //      this.service.flushPacket();
            System.exit(0);
        }
    /**
     * Writes the outgoing packet to the game console.
     * @param msg the actual packet message.
     */
        public void writeToConsoleOutBound(String msg)  {
            this.gameConsole.append(Integer.toString(packetNumber++) + ": SENDING: " + msg + "\n");
        }
    /**
     * Writes the incoming packet to the game console.
     * @param msg the actual packet message.
     */
        public void writeToConsoleInBound(String msg)   {
            this.gameConsole.append(Integer.toString(packetNumber++) + ": RECEIVING: " + msg + "\n");
        }
    /**
     * Writes an error to the game console.
     * @param msg the error message.
     */
        public void writeToConsoleError(String msg) {
            this.gameConsole.append("Error handling packet number " + Integer.toString(packetNumber) + "." + msg + "\n");
        }
    /**
     * Flips a Card object and show an image
     * @param whichCard the card ID which will be flipped.
     * @param imgID the image which will be shown on the flipped card.
     */
        public void flipCard(int whichCard, int imgID)  {
            this.cards.get(whichCard).flipCard(imgID);
        }
    /**
     * Accumulates points.
     * @param amt the amount to be added.
     */
        public void gainPoints(int amt) {
            this.points += amt;
        }
        public void enableTurn()    {
            this.isTurn = true;
        }
        public void disableTurn()   {
            this.isTurn = false;
        }
    }
    

1 个答案:

答案 0 :(得分:0)

您与套接字的连接有效,因为它位于构造函数中,没有调用已修改的元素(比如更新按钮的文本)。您的客户端服务需要一个循环来等待UI发出的请求,否则您需要创建一个包含UI发出的每个请求的线程。它将成为一个瓶颈,特别是在一个用户操作可以触发多个UI更新的游戏中。看看发布的代码你应该或多或少地遵循这种模式

package so;

import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

class ClientService implements Runnable{
    JLabel label; 
    ConcurrentLinkedQueue<Long> work;

    @Override
    public void run() {
        Long i = null;
        try{
            while(true){
                if ((i = work.poll()) != null){
                    final long ii = i;
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            label.setText(ii + "");
                        }
                      });
                }
                Thread.sleep(10);
            }
        }
        catch(Exception x){

        }
    }

}

class GameClient extends JFrame{

    Thread worker;
    ConcurrentLinkedQueue<Long> work;
    private JLabel label;
    private JButton button;

    GameClient(){
        setLayout(new GridLayout(2, 1));
        label = new JLabel("Label");
        button = new JButton("Button");
        button.addMouseListener(new MouseListener(){

            @Override
            public void mouseClicked(MouseEvent e) {
                work.add(System.currentTimeMillis());
            }

            @Override
            public void mousePressed(MouseEvent e) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseReleased(MouseEvent e) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseEntered(MouseEvent e) {
                // TODO Auto-generated method stub

            }

            @Override
            public void mouseExited(MouseEvent e) {
                // TODO Auto-generated method stub

            }

        });
        this.add(label);
        this.add(button);
        work = new ConcurrentLinkedQueue<Long>();
        ClientService cs = new ClientService();
        cs.label = this.label;
        cs.work = this.work;
        this.worker = new Thread(cs);
        this.worker.start();
    }
}

class SOCLass {

    public static void main(String[] args){
        SOCLass m = new SOCLass();
        GameClient frame = new GameClient();
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                frame.worker.interrupt();
                System.exit(0);
            }
        });
        frame.pack();
        frame.setVisible(true);
    }   
}
相关问题