客户端没有收到服务器发来的消息(Socket编程)

问题描述 投票:0回答:1

每个游戏周期,服务器希望使用

sendGameWorldSections()
方法向每个连接的客户端发送一条消息。它在一个新线程中执行此操作,以便游戏代码保持运行并且不会阻塞线程。当调用静态方法
Server.sendMessageToPlayer(playerID,gameWorldSectionString);
时,该方法旨在获取
Socket
HashMap<String,Socket> playerIDToSocket
,然后获取其
OutputStream
,并将消息发送到该客户端。
playerIDToSocket
映射将
playerID
(作为字符串)映射到
Socket
。它存储playerID和Socket的方式是:服务器接受客户端的连接,客户端单独发送一条消息作为
JSONObject
,只说明刚刚连接的玩家的PlayerID,然后服务器将其存储起来,使用
Socket
进入哈希映射。客户端应该将收到的每条消息打印到控制台上。当服务器将消息发送到客户端(游戏世界部分)时,客户端永远不会收到该消息。但有时,当我停止客户端程序时,它只会批量打印自连接以来收到的每一条消息。是不是某个地方堵住了?我似乎无法解决这个问题。

GameTicker 类:

package GameEngine;

import GameEngine.Game.PlayerManager;
import GameEngine.Game.World;
import GameEngine.Network.Server;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;


public class GameTicker extends Thread{

    public final long GAME_TICK = 2000000000; // The smallest unit of time in the game. (0.2s)
    public int ticksPassed = 0;


    /**
     * This is the beating heart of the game engine. It controls the game state, receives inputs, and informs the outputter
     * to send stuff to clients.
     *
     * Takes inputs of the current tick and then processes them (same thread)
     *
     * After each tick end, send messages to all clients informing them of the new sections.
     *
     *
     */
    @Override
    public void run() {
        long gameStartTime = System.nanoTime();
        long lastTickEnd = System.nanoTime();
        while(true){
            if(System.nanoTime() - lastTickEnd >= GAME_TICK){

                //GameStateManager.performPlayerActions();
                //GameStateManager.performGameWorldActions(); //
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            sendGameWorldSections();
                        } catch (JSONException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }).start();
                lastTickEnd = System.nanoTime();
                ticksPassed++;
                System.out.println(">>GAME TICKER: Tick passed. #" + ticksPassed );
            }
        }
    }

    /**
     * Sends  sections of the game to each player that is logged in.
     * @throws JSONException
     */
    public void sendGameWorldSections() throws JSONException {
        System.out.println("Sending game world sections..");
        for(int i = 0; i < PlayerManager.loggedInPlayerIDs.size(); i++){

            String playerID = PlayerManager.loggedInPlayerIDs.get(i);

            int xP = PlayerManager.players.get(playerID).getX(); // Position x of player
            int yP = PlayerManager.players.get(playerID).getY(); // Position y of player
            int zP = PlayerManager.players.get(playerID).getZ();

            long start = System.currentTimeMillis();
            JSONObject gameWorldSectionJSON = null;
            try {
                gameWorldSectionJSON = World.getGameWorldSection(zP,xP,yP);
            } catch (JSONException e) {
                throw new RuntimeException(e);
            }
            System.out.println(System.currentTimeMillis() - start + "MS to get JSON of section.");
            try {
                gameWorldSectionJSON.put("RESULT","GAME_WORLD_SECTION");
            } catch (JSONException e) {
                throw new RuntimeException(e);
            }
            String gameWorldSectionString = gameWorldSectionJSON.toString();
            try {
                Server.sendMessageToPlayer(playerID,gameWorldSectionString);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }

}

服务器类:

package GameEngine.Network;

import GameEngine.Game.Player;
import GameEngine.Game.PlayerManager;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.HashMap;

// Server class

public class Server extends Thread{
    /**
     * We must have:
     * - Player ID -> InetAddress
     */

    /**
     * STEP 1: Client connects to the server.
     * STEP 2: Client sends its user ID. The server then adds its inetaddress to the list. This is called Logging in.
     *
     * STEP 3..n:
     * - Client makes requests to the server, which the ClientHandler handles the message then replies
     * - Server can send message to a client or multiple clients.
     */

    public static HashMap<String, Socket>  playerIDToSocket = new HashMap<>(); // THESE ARE LOGGED IN.

    public void run()
    {
        listenForConnections();
    }
    private void listenForConnections(){
        ServerSocket server = null;
        try {

            server = new ServerSocket(1234);
            server.setReuseAddress(true);

            while (true) {
                Thread.sleep(1);

                Socket client = server.accept();


                System.out.println("New client connected"
                        + client.getInetAddress()
                        .getHostAddress());

                ClientHandler connectedClient = new ClientHandler(client);

                connectedClient.start();
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }


    }
//    public void sendMessagesToPlayers() throws InterruptedException, IOException {
//        while(true){
//            Thread.sleep(1);
//            for(int i = 0; i < messagesToPlayers.size(); i++){
//                ClientMessage clientMessage = messagesToPlayers.get(i);
//                PrintWriter out = new PrintWriter(clientMessage.getSocket().getOutputStream(), true);
//                out.print(clientMessage.getMessage());
//                out.flush();
//            }
//        }
//    }

    public static void sendMessageToPlayer(String playerID, String message) throws IOException {
        System.out.println("Sending message..");
        Socket socket = playerIDToSocket.get(playerID);
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        out.print(message);
    }



    private class ClientHandler extends Thread {
        private final Socket clientSocket;

        // Constructor
        public ClientHandler(Socket socket)
        {
            this.clientSocket = socket;
        }

        public void run()
        {

            try {

                PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
                BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

                String line;
                while(true) {
                    Thread.sleep(1);
                    while ((line = in.readLine()) != null) {

                        // writing the received message from
                        // client
                        System.out.printf(" Sent from client "+ clientSocket +": %s\n", line);
                        JSONObject request = new JSONObject(line);
                        switch (request.getString("COMMAND")) {
                            case "SEND_SOCKET_DATA":
                                String playerID = request.getString("PLAYER_ID");
                                playerIDToSocket.put(playerID, clientSocket);
                                PlayerManager.loggedInPlayerIDs.add(playerID);
                                break;
                        }
                        out.println("You are now logged in.");
                    }
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                throw new RuntimeException(e);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

客户端类:

package Network;

import Game.Entities.Doorway;
import Game.Entities.EmptyBlock;
import Game.Entities.GraphicEntity;
import Game.GameWorldSection;
import Game.Player;
import Game.Tile;
import Graphics.SpriteData;
import jdk.jshell.execution.Util;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import javax.swing.text.Utilities;
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;

public class Client extends Thread{


    // driver code

    private static Socket socket;
    public static boolean isJSONValid(String test) {
        try {
            new JSONObject(test);
        } catch (JSONException ex) {
            // edited, to include @Arthur's comment
            // e.g. in case JSONArray is valid as well...
            try {
                new JSONArray(test);
            } catch (JSONException ex1) {
                return false;
            }
        }
        return true;
    }

    public void listen(BufferedReader in){

        // Listening for server messages
        try {
            String message = in.readLine();
            System.out.println("[SERVER]: "
                    +message);
            if(isJSONValid(message)){
                JSONObject json = new JSONObject(message);
                switch(json.getString("RESULT")) {
                    case "GAME_WORLD_SECTION":
                        // Clear the tiles
                        GameWorldSection.clearTiles();
                        Tile[][] tiles = GameWorldSection.getTiles();
                        JSONObject coordinates = json.getJSONObject("COORDINATES");
                        Iterator<String> coordinatesIterator = coordinates.keys();
                        while (coordinatesIterator.hasNext()) {
                            String coordinateKey = coordinatesIterator.next();
                            JSONObject coordinateJSON = coordinates.getJSONObject(coordinateKey);
                            int real_x = Integer.parseInt(coordinateKey.split(",")[0]);
                            int real_y = Integer.parseInt(coordinateKey.split(",")[1]);
                            int painted_x = real_x - json.getInt("LOWEST_X");
                            int painted_y = real_y - json.getInt("LOWEST_Y");
                            JSONArray entities = coordinateJSON.getJSONArray("ENTITIES");
                            for (int i = 0; i < entities.length(); i++) {
                                JSONObject playerObj = entities.getJSONObject(i);
                                switch (playerObj.getString("NAME")) {
                                    case "EMPTY_BLOCK":
                                        tiles[painted_x][painted_y].addEntity(new EmptyBlock());
                                        break;
                                    case "TUTORIAL_FLOOR":
                                        tiles[painted_x][painted_y].addEntity(new GraphicEntity(SpriteData.SPRITE_NAME.TUTORIAL_GROUND));
                                        break;
                                    case "DOORWAY":
                                        tiles[painted_x][painted_y].addEntity(new Doorway(SpriteData.SPRITE_NAME.DOORWAY));
                                        break;
                                    case "PLAYER":
                                        SpriteData.SPRITE_NAME spriteName = null;

                                        boolean isMoving = playerObj.getBoolean("IS_MOVING");
                                        switch (playerObj.getString("DIRECTION_FACING")) {
                                            case "NORTH":
                                                if (isMoving) {
                                                    spriteName = (SpriteData.SPRITE_NAME.CHARACTER_WALKING_NORTH);
                                                } else {
                                                    spriteName = (SpriteData.SPRITE_NAME.CHARACTER_FACING_NORTH);
                                                }
                                                break;
                                            case "WEST":
                                                if (isMoving) {
                                                    spriteName = (SpriteData.SPRITE_NAME.CHARACTER_WALKING_WEST);
                                                } else {
                                                    spriteName = (SpriteData.SPRITE_NAME.CHARACTER_FACING_WEST);
                                                }
                                                break;
                                            case "SOUTH":
                                                if (isMoving) {
                                                    spriteName = (SpriteData.SPRITE_NAME.CHARACTER_WALKING_SOUTH);
                                                } else {
                                                    spriteName = (SpriteData.SPRITE_NAME.CHARACTER_FACING_SOUTH);
                                                }
                                                break;
                                            case "EAST":
                                                if (isMoving) {
                                                    spriteName = (SpriteData.SPRITE_NAME.CHARACTER_WALKING_EAST);
                                                } else {
                                                    spriteName = (SpriteData.SPRITE_NAME.CHARACTER_FACING_EAST);
                                                }
                                                break;
                                        }
                                        tiles[painted_x][painted_y].addEntity(new Player(spriteName));
                                        break;
                                }
                            }
                        }
                }
            }
            else{
                //
            }

            } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }
    public void run()
    {
        // establish a connection by providing host and port
        // number


        try {
            socket = new Socket("localhost", 1234);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            // reading from server
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));


            JSONObject clientData = new JSONObject();
            clientData.put("COMMAND","SEND_SOCKET_DATA");
            clientData.put("PLAYER_ID","123");
            out.println(clientData.toString());
            out.flush();
            while(true) {
                listen(in);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }catch(JSONException e) {
        }
        // writing to server
    }

}
java sockets server client
1个回答
0
投票

在此方法中:您正在使用 out.print (message) ,但这不会刷新数据,因为当您使用“true”初始化它时,刷新仅发生在 PrintWriter 中的 printf、format 或 println 上。

您应该添加“out.flush();”就在out.print之后。

public static void sendMessageToPlayer(String playerID, String message) throws IOException {
        System.out.println("Sending message..");
        Socket socket = playerIDToSocket.get(playerID);
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        out.print(message);
        out.flush();
    }
© www.soinside.com 2019 - 2024. All rights reserved.