【问题标题】:Server Side Client Side JAVA game moves服务器端客户端JAVA游戏动作
【发布时间】:2019-10-13 22:11:37
【问题描述】:

我是服务器-客户端编码的新手。我有一个制作 3 块石头游戏的项目,我应该在客户端和服务器之间建立连接。我将客户端连接到服务器,但我不知道如何将客户端的移动(点的坐标)传递给服务器,然后将正确的消息从服务器返回给客户端。而且我不知道什么是 byte[] 数据也是 BUFFSize 你能解释一下为什么我还必须使用 byte[] BUFFSIZE 吗?我怎么能把客户放在板上的石头放在服务器上呢? CilentSide:

public class ThreeStonesGameClientSide {

    private static final int BUFSIZE = 32;
    private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(ThreeStonesGameClientSide.class);
    private String ip;
    private int port;

    public ThreeStonesGameClientSide(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }
    public void connectToServer() throws IOException {
        Socket socket = new Socket(this.ip, this.port);  
        LOG.info("Connected to the server");
        InputStream in = socket.getInputStream();
        OutputStream out = socket.getOutputStream();

       Point recivedPoint = new Point();
       int x = (int) recivedPoint.getX();
       int y = (int) recivedPoint.getY();

       byte[] data = new byte[BUFSIZE];
        // Receive the same string back from the server
        int totalBytesRcvd = 0;  // Total bytes received so far
        int bytesRcvd;           // Bytes received in last read
        while (totalBytesRcvd < data.length) {
            if ((bytesRcvd = in.read(data, totalBytesRcvd,
                    data.length - totalBytesRcvd)) == -1) {
                throw new SocketException("Connection closed prematurely");
            }
            totalBytesRcvd += bytesRcvd;
        }  // data array is full

        System.out.println("Received: " + new String(data));

        socket.close();  // Close the socket and its streams 

    }

}

这是服务器端

public class ThreeStonesGameClientSide {

    private static final int BUFSIZE = 32;
    private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(ThreeStonesGameClientSide.class);
    private String ip;
    private int port;

    public ThreeStonesGameClientSide(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }
    public void connectToServer() throws IOException {
        Socket socket = new Socket(this.ip, this.port);  
        LOG.info("Connected to the server");
        InputStream in = socket.getInputStream();
        OutputStream out = socket.getOutputStream();

       Point recivedPoint = new Point();
       int x = (int) recivedPoint.getX();
       int y = (int) recivedPoint.getY();

       byte[] data = new byte[BUFSIZE];
        // Receive the same string back from the server
        int totalBytesRcvd = 0;  // Total bytes received so far
        int bytesRcvd;           // Bytes received in last read
        while (totalBytesRcvd < data.length) {
            if ((bytesRcvd = in.read(data, totalBytesRcvd,
                    data.length - totalBytesRcvd)) == -1) {
                throw new SocketException("Connection closed prematurely");
            }
            totalBytesRcvd += bytesRcvd;
        }  // data array is full

        System.out.println("Received: " + new String(data));

        socket.close();  // Close the socket and its streams 

    }

}

这是 Board 类

public class Board implements Serializable {

    public final IntegerProperty numOfWhiteStones;
    public final IntegerProperty numOfBlackStones;
    public final ObjectProperty<Stone[][]> board;

    private Point lastPoint;

    public Board(Player p1, Player p2) {
        this.numOfBlackStones = new SimpleIntegerProperty();
        this.numOfWhiteStones = new SimpleIntegerProperty();
        this.board = new SimpleObjectProperty<Stone[][]>(new Stone[11][11]);
    }

    /**
     * Checks if chosen point is along the same x and y axis as the last placed point.
     * @param placementPoint
     * @return 
     */
    public boolean checkSlot(Point placement) {
        Stone[][] board = getBoard();
        int x = placement.x;
        int y = placement.y;
        // Check if placement is within the limits of the inner arry
        if ((x < 0 || x > board.length - 1) && (y < 0 || y > board.length - 1)) {
            return false;
        }
        // Check if place on board is empty
        if (board[x][y] != Stone.EMPTY) {
            return false;
        }
        if (lastPoint == null){
            return true;
        }
        // Check if placement is within the same colum or row as the last played stone
        return (x == lastPoint.x ^ y == lastPoint.y);

    }

    public void placeStone(Point placement, Stone stone) {
        Stone[][] board = getBoard();
        int x = placement.x;
        int y = placement.y;
        board[x][y] = stone;
        if (stone == Stone.BLACK) {
            numOfBlackStones.add(1);
        } else {
            numOfWhiteStones.add(1);
        }
        lastPoint = placement;
    }

    public int calculatePointsFor(Stone stone) {
        Stone[][] board = this.board.get();
        int counter = 0;
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board.length; j++) {
                for (int k = 0; k < 4; k++) {
                    if (directionCheck(stone, new Point(i, j), k)){
                        counter++;
                    }
                }
            }
        }
        return counter;
    }

    boolean directionCheck(Stone stone, Point coord, int direction) {
        Stone[][] board = getBoard();
        int x = coord.x;
        int y = coord.y;
        switch (direction) {
            case 0:
                if (coord.x + 2 < board.length) {
                    return (board[x][y] == board[x + 1][y] && board[x + 1][y] == board[x + 2][y]);
                }
                break;
            case 1:
                if ((coord.x + 2 < board.length) && (coord.y + 2 < board.length)) {
                    return (board[x][y] == board[x + 1][y + 1] && board[x + 1][y + 1] == board[x + 2][y + 2]);
                }
                break;
            case 2:
                if (coord.y + 2 < board.length) {
                    return (board[x][y] == board[x][y + 1] && board[x][y + 1] == board[x][y + 2]);
                }
                break;
            case 3:
                if ((coord.x - 2 >= 0) && (coord.y + 2 < board.length)) {
                    return (board[x][y] == board[x - 1][y + 1] && board[x - 1][y + 1] == board[x - 2][y + 2]);
                }
                break;

        }
        return false;
    }

    public final Stone[][] getBoard() {
        return board.get();
    }

    public void setBoard(final Stone[][] isbn) {
        this.board.set(isbn);
    }

    public final ObjectProperty boardProperty() {
        return board;
    }

    public final int getNumOfWhiteStones() {

        return numOfWhiteStones.get();
    }

    public final IntegerProperty numOfWhiteStonesProperty() {
        return numOfWhiteStones;
    }

    public final int getNumOfBlackStones() {
        return numOfBlackStones.get();
    }

    public final IntegerProperty numOfBlackStonesProperty() {
        return numOfBlackStones;
    }

    public final Point getLastPoint() {
        return lastPoint;
    }

}

【问题讨论】:

  • 最简单的方法就是将移动发送到一个字符串中,例如“MOVE x=1,y=3;”到服务器。
  • 对于您关于BUFSIZE 的问题,如果您不自己分配缓冲区会更容易。让 API 来做。将您的输出流包装在 BufferedWriter 中并发送字符串,如果可以避免的话,请不要弄乱缓冲区。
  • 您执行Point recivedPoint = new Point();,然后从中获取X 和获取Y - 这显然不会包含有效数据。您需要决定的第一件事是将电路板的当前状态存储在哪里 - 在客户端(在这种情况下,您必须每次都将其发送到服务器 - 即服务器是无状态的)或在服务器中(在这种情况下,记住几个游戏可能同时进行,所以你需要“记住”每个客户端;这就是 JSESSION cookie 对 tomcat 所做的,等等)

标签: java sockets server-communication


【解决方案1】:

对于您的问题,恕我直言:

  1. 通过网络发送的所有数据都应该是字节数组,它涉及字节顺序(字节序),您可以在Wiki中查看更多定义。如果它在字节数组中,您可以做一些技巧使其尽可能小。在网络中,可能会出现很多问题,因此数据传输越少,就越难丢失。对于字节数据的传输,你可以在这里查看我的小函数:Pack data with Msgpack librariesEndianness converting

  2. 您创建的服务器应处理游戏中的所有逻辑,而客户端仅供查看。例如:当客户移动时,他只发送他的动作(移动对象的ID,新对象的目标,...)。之后,服务器必须确认消息的信息,自己进行计算并将结果返回给所有相应的客户端。我写了一个小项目,所以您可以查看示例以获取更多详细信息:NIO java server game framework with examples

【讨论】:

    猜你喜欢
    • 2015-03-24
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 1970-01-01
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多