代码之家  ›  专栏  ›  技术社区  ›  Jamie Keeling

JAVA -人可玩服务器/客户端多人游戏机

  •  0
  • Jamie Keeling  · 技术社区  · 14 年前

    我目前正在尝试实施 Nim 使用Java,我希望能够有一个玩家充当服务器,另一个作为玩家。

    对于Java网络来说,我是相当新的,并且只有使用TCP/IP的经验,在那里,人类客户端连接到计算机主机。

    我的问题是,我需要能够区分不同的玩家,同时实现游戏的协议(协议是游戏的逻辑)。

    现在,我可以让一个玩家(客户机)与服务器交互。所发生的一切是客户端可以玩游戏,但没有反对(服务器只跟踪游戏的状态,如还剩多少杆,有效输入等)。

    我该如何添加第二个玩家来取代主机?

    编辑:

    客户机和服务器代码已经发布,这是我使用的代码,我很满意,我问的问题是,它是一个合适的基础来实现一个多人游戏,还是我需要做一些完全不同的事情?

    我的NIM协议:(未测试)

    public class NimLogic 
    {
        private static final int WAITING = 0;
        private static final int EVALUATING = 1;
        private static final int ANOTHER = 2;
        private int currentState = WAITING;
        private int theInput = 0;
        private int totalSticks = 10;
    
        String processInput(String input) {
            String theOutput = null;
    
            try 
            {
                theInput = Integer.parseInt(input);
            } 
            catch (Exception e) 
            {
                // Ignore conversion error
            }
    
            switch (currentState) 
            {
            case WAITING:
                theOutput = "Take how many sticks?";
                currentState = EVALUATING;
                break;
    
            case EVALUATING:
    
                if(theInput == 1 | theInput == 2 | theInput == 3)
                {
                    if (theInput < totalSticks) 
                    {
                        totalSticks -= theInput;
                        theOutput = "There are" + totalSticks + " left.";
                    } 
                    else if (theInput > totalSticks) 
                    {
                        theOutput = "Error: You cannot take more sticks than that are available";
                        currentState = EVALUATING;
                    } 
                }
    
                if(totalSticks == 1)
                {
                    theOutput = "Game Over! Play again? (Yes = 1, No = 0)...";
                    currentState = ANOTHER;
                }
                break;
    
            case ANOTHER:
                if (theInput == 1) 
                {
                    totalSticks = 10;
                    currentState = EVALUATING;
                    theOutput = "Take how many sticks?";
                } 
                else 
                {
                    theOutput = "Bye.";
                }
            }
            return theOutput;
        }
    }
    

    谢谢你的帮助!

    编辑:

    顾客

    public class Client
    {
       @SuppressWarnings("static-access")
    public static void main(String machine[])
       {
          Socket kkSocket = null;
          PrintStream os = null;
          DataInputStream is = null;
    
          try
          {
             kkSocket = new Socket(machine[0], 4444);
             os = new PrintStream(kkSocket.getOutputStream());
             is = new DataInputStream(kkSocket.getInputStream());
          }
          catch(UnknownHostException e)
          {
             System.err.println("Socket Connect failed on " + machine[0]);
          }
          catch (IOException e)
          {
             System.err.println("Streams failed on " + machine[0]);
          }
    
          if (kkSocket != null && os != null && is != null )
          {
             try
             {
                 String fromServer, fromClient;
    
                 while((fromServer = is.readLine()) != null && !fromServer.equals("Bye."))
                 {
                    fromClient = JOptionPane.showInputDialog(fromServer);
                    os.println(fromClient);
                 }
                 JOptionPane.showMessageDialog(null, "Goodbye, keep smiling.");
                 os.close();
                 is.close();
                 kkSocket.close();
              }
    
             catch (UnknownHostException e)
             {
                System.err.println("Can't connect to " + machine[0] + e);
             }
             catch (IOException e)
             {
                e.printStackTrace();
                System.err.println("I/O failed on " +machine[0]);
             }
          }
       }
    }
    

    服务器

    public class Server
    {
       public static void main(String arg[])
       {
          ServerSocket serverSocket = null;
    
          try
          {
             serverSocket = new ServerSocket(4444);
          }
          catch (IOException e)
          {
             System.err.println("Can't listen on 4444 -> " + e);
             System.exit(1);
          }
    
          Socket clientSocket = null;
          try       // allow the client to connect
          {
             clientSocket = serverSocket.accept();
          }
          catch (IOException e)
          {
             System.err.println("Failed accept on 4444 -> " + e);
             System.exit(1);
          }
    
          try
          {
             DataInputStream is =
                new DataInputStream(new BufferedInputStream
                               (clientSocket.getInputStream()));
             PrintStream os =
                new PrintStream(new BufferedOutputStream
                  (clientSocket.getOutputStream(), 1024), false);
             GuessState kks = new GuessState();
             String inputLine, outputLine;
    
             outputLine = kks.processInput(null);
             os.println(outputLine);
             os.flush();
    
             while((inputLine = is.readLine()) != null
                    && !outputLine.equals("Bye."))
             {
                outputLine = kks.processInput(inputLine);
                os.println(outputLine);
                os.flush();
             }
             os.close();
             is.close();
             clientSocket.close();
             serverSocket.close();
          }
          catch (IOException e)
          {
             e.printStackTrace();
          }
       }
    }
    
    2 回复  |  直到 11 年前
        1
  •  1
  •   Paul Russell    14 年前

    我不太确定我是否在这里回答你的问题,所以如果我不回答,请道歉。而且,自从我做了Java网络代码以来,已经有一段时间了,所以这里可能会有一些皱纹,希望其他人能整理出来。

    下面是我可能做出的改变的一个大脑垃圾堆,不管是好是坏……

    • 重新编写网络代码以接受多个连接。通常,您可以通过将serversocket.accept返回的套接字交给一个要处理的线程来完成此操作。如果您处理的是大量的连接,那么您可以使用NIO来代替,但这对于现在来说可能太快了。
    • 将游戏状态与客户端会话代码分开。为了保持简单,将客户机会话代码嵌入到线程对象中。游戏状态需要在为套接字提供服务的所有线程之间共享的对象中。
    • 我建议让游戏状态成为一个适当的“域对象”,而不是让它解析字符串等。它应该有“take(clientid,int)”之类的操作,而不是“processinput”。
    • 考虑使用 observer pattern 将事件从域对象分发到套接字线程。事件的例子可能是“turnstake”或“gamecomplete”。
    • 将“turns”的概念嵌入到游戏对象中,并让服务器向套接字线程广播一个事件,通知该事件属于谁。

    希望能给你一个十元的开胃菜?

        2
  •  1
  •   Amir Afghani    14 年前

    服务器/客户机方面不应影响两个参与者的通信。您应该能够生成NIM游戏的两个实例,一个实例监听某个端口(服务器)上的传入连接,另一个实例连接到该端口(客户机)。一旦建立了连接,就可以通过表示游戏信息的连接在两个实例之间传递对象。NIM游戏的每个实例都负责解析该游戏数据并在其上运行NIM逻辑。

    本质上,游戏的每个实例都可以作为服务器或客户机运行。这是我为国际象棋编写的一些适用的代码。通读一遍。在其他地方,我实例服务器或客户机并将其存储在类型的引用中 NetworkIdenitity .

       private abstract class NetworkEntity
            extends Thread {
    
            ObjectOutputStream outputStream;
    
            ObjectInputStream inputStream;
    
            Socket connectionHandle;
    
            Object messageToSend;
    
            Object receivedMessage;
    
            public NetworkEntity(final String name) {
    
                super(name);
    
            }
    
            @Override
            public abstract void run();
    
            public void getStreams()
                    throws IOException {
                this.outputStream = new ObjectOutputStream(this.connectionHandle.getOutputStream());
                this.outputStream.flush();
                this.inputStream = new ObjectInputStream(this.connectionHandle.getInputStream());
            }
    
            public void closeConnection() {
    
                try {
                    if (this.outputStream != null) {
                        this.outputStream.close();
                    }
                    if (this.inputStream != null) {
                        this.inputStream.close();
                    }
                    if (this.connectionHandle != null) {
                        this.connectionHandle.close();
                        chatPanel.writeToDisplay("Connection closed with "
                                + this.connectionHandle.getInetAddress().getHostName());
                    }
                }
                catch (final IOException e) {
                    JOptionPane.showMessageDialog(thisFrame, "Problems experienced when closing connection",
                            "Notification", JOptionPane.ERROR_MESSAGE);
                }
    
            }
    
            public void processIncomingData()
                    throws IOException {
    
                do {
                    try {
                        this.receivedMessage = this.inputStream.readObject();
                    }
                    catch (final ClassNotFoundException e) {
                        JOptionPane.showMessageDialog(thisFrame, "read() error: message from "
                                + this.connectionHandle.getInetAddress().getHostName() + " not received", "Notification",
                                JOptionPane.ERROR_MESSAGE);
                    }
                    if (this.receivedMessage instanceof Move) {
                        final Move m = (Move) this.receivedMessage;
                        System.out.println(getName() + " got move" + m);
                        requestMove(Table.this.chessBoard, Table.this.currentPlayer, Table.this.currentOpponent, m, false);
                        repaint();
                    }
                    else if (this.receivedMessage instanceof Board) {
                        final Board b = (Board) this.receivedMessage;
                        System.out.println(getName() + " received this board:");
                        b.printCurrentBoardState();
                        // System.out.println("local copy looked like this: " );
                        // chessBoard.printCurrentBoardState();
                        // chessBoard.setGameBoard(b.getGameBoard());
                        // switchCurrentPlayer();
                        // chessBoard.updateBoardState(currentPlayer,
                        // currentOpponent);
                        repaint();
                    }
                    else if (this.receivedMessage instanceof String) {
                        chatPanel.writeToDisplay((String) this.receivedMessage);
                    }
                } while (/* !message.equals("SERVER>>> TERMINATE") */true);
    
            }
    
            public void sendData(final Object obj_to_send) {
                try {
                    this.outputStream.writeObject(obj_to_send);
                    this.outputStream.flush();
                }
                catch (final IOException e) {
    
                }
            }
    
        }
    
        private final class Client
            extends NetworkEntity {
    
            private final String hostName;
    
            private final int serverPort;
    
            public Client(final String host, final int port) {
                super("CLIENT");
                this.hostName = host;
                this.serverPort = port;
            }
    
            @Override
            public void run() {
                try {
                    connectToServer();
                    getStreams();
                    processIncomingData();
                }
                catch (final EOFException eof) {
                }
                catch (final IOException ioe) {
                }
                catch (final NullPointerException npe) {
                }
                finally {
                    closeConnection();
                }
            }
    
            private void connectToServer()
                    throws IOException {
                try {
                    this.connectionHandle = new Socket(InetAddress.getByName(this.hostName), this.serverPort);
                    connectionEstablished = true;
                    chatPanel.writeToDisplay("Successfully connected to "
                            + this.connectionHandle.getInetAddress().getHostName());
                }
                catch (final IOException e) {
                    chatPanel.writeToDisplay("Failed to connect to: " + this.hostName);
                }
            }
    
        }
    
        private final class Server
            extends NetworkEntity {
    
            private ServerSocket server;
    
            private final int listenPort;
    
            public Server(final int listen_port) {
                super("SERVER");
                this.listenPort = listen_port;
            }
    
            @Override
            public void run() {
    
                try {
                    this.server = new ServerSocket(this.listenPort, 1);
                    chatPanel.writeToDisplay("Listening on port " + this.listenPort);
                    try {
                        waitForConnection();
                        getStreams();
                        processIncomingData();
                    }
                    catch (final EOFException eof) {
                        // System.out.println(getName() + "exception: " +eof);
                        // eof.printStackTrace();
                    }
                    catch (final IOException ioe) {
                        // System.out.println(getName() + "exception: " +ioe);
                        // ioe.printStackTrace();
                    }
                    finally {
                        closeConnection();
                    }
                }
                catch (final IOException e) {
                    JOptionPane.showMessageDialog(thisFrame, "Network Error: " + e, "Notification",
                            JOptionPane.ERROR_MESSAGE);
                }
    
            }
    
            private void waitForConnection()
                    throws IOException {
    
                this.connectionHandle = this.server.accept();
                connectionEstablished = true;
                chatPanel.writeToDisplay("Connection received from:" + this.connectionHandle.getInetAddress().getHostName());
    
            }
    
            @Override
            public void closeConnection() {
    
                super.closeConnection();
    
                try {
                    this.server.close();
                }
                catch (final IOException e) {
                    chatPanel.writeToDisplay(getName() + "failed to disconnect from the network");
                }
    
            }