为什么我的数据报套接字停止接收数据,即使它接收数据完全正常?

时间:2013-06-21 03:20:40

标签: java sockets network-programming datagram

我正在使用java进行多人游戏,我在这里确实遇到了一些问题。出于某种原因,我的数据报套接字将停止接收从客户端设置的数据包,即使根据控制台,它之前完全收到它们。我不太了解网络或使用套接字进行编程,所以这让我很难过。

这是我的代码:

服务器:

package server;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;

import shared.BaseEntity;
import shared.MethodNotOverridenException;
import shared.Packet;
import shared.Player;

public class S_GameLoop implements Runnable{
    //Constants
    private static final int TICKS_PER_SECOND = 25;
    private static final int TICKS_TO_SKIP = 1000 / TICKS_PER_SECOND;
    private static final int MAX_FRAMESKIP = 5;
    private static final int SPAWN_COORD_X = 50;
    private static final int SPAWN_COORD_Y = 50;

    private Vector<S_Client> ClientList;
    private Map<Integer, BaseEntity> EntityMap;
    private AtomicInteger IDGenerator;

    private boolean gameIsRunning = true;
    private DatagramSocket socket;
    byte[] recieveData = new byte[1024];
    byte[] prevRecieveData = new byte[1024];

    private int port;
    private int loops;

    public S_GameLoop(int port) {
        ClientList = new Vector<S_Client>();
        this.port = port;
        IDGenerator = new AtomicInteger();
        EntityMap = new HashMap<Integer, BaseEntity>();
    }

    private void Init() throws SocketException {
        System.out.println("INIT");
        socket = new DatagramSocket(port);
        System.out.println("[Server] Create listen server on " + socket.getLocalAddress().getHostAddress() + " on port " + socket.getLocalPort());
        socket.setSoTimeout(0);
    }

    private void Running() {
        System.out.println("S_GameLoop staring");
        long nextGameTick = System.currentTimeMillis();

        DatagramPacket recievePacket = new DatagramPacket(recieveData, recieveData.length);

        //GameLoop goes here
        while(gameIsRunning) {
            loops = 0;

            //Receive the data
            try {
                socket.receive(recievePacket);
            } catch (IOException e1) {
                e1.printStackTrace();
            }

            while(System.currentTimeMillis() > nextGameTick && loops < MAX_FRAMESKIP) {
                try {
                    Update(recievePacket);
                } catch (MethodNotOverridenException | IOException e) {
                    System.err.println(e);
                }

                nextGameTick += TICKS_TO_SKIP;
                loops++;
            }

            nextGameTick += TICKS_TO_SKIP;
            loops++;

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void Update(DatagramPacket recievePacket) throws IOException, MethodNotOverridenException {
        if(prevRecieveData != recieveData) {
            parseData(formatData(recievePacket.getData()), recievePacket);
            prevRecieveData = recieveData;
        } else {
            return;
        }
    }

    public static Packet formatData(byte[] data) {
        try {
            if(data[1] == 0);
            String tag = new String(Arrays.copyOfRange(data, 1, 8));
            System.out.println("[Server] Recieved packet " + data[0] + " " + new String(tag));
            return new Packet(data[0],tag.getBytes(), Arrays.copyOfRange(data, 8, data.length));
        } catch (ArrayIndexOutOfBoundsException e) {
            return new Packet((byte)0, new byte[0], new byte[0]);
        }
    }

    private void parseData(Packet p, DatagramPacket recievePacket) throws IOException, MethodNotOverridenException {
        if(p.getTag() == new byte[0]) {
            System.out.println("[Server] Recieved NULL packet");
            return;
        }
        switch (p.getTagAsString()) {
            case "LGN_RQS": System.out.println("[Server] Login Request Recieved");
                            //Login was accepted
                            //Create a Client ref, and add it to the vector
                            S_Client newClient = new S_Client(recievePacket.getAddress(), recievePacket.getPort());
                            ClientList.add(newClient);

                            //Create a player and add it to Entity list
                            Player newPlayer = new Player(IDGenerator.getAndIncrement(), ClientList.indexOf(newClient));
                            EntityMap.put(newPlayer.getEntID(), newPlayer);
                            System.out.println("[Server] Created new Player with EID " + newPlayer.getEntID() + " and CID " + newPlayer.getCID());
                            //Send reply to Client that is logging in
                            sendData(new Packet((byte)2, "LGN_ACP".getBytes(), ("CID;" + ClientList.indexOf(newClient) + ";EID;" + newPlayer.getEntID()).getBytes()).getBytes(), newClient.getIp(), newClient.getPort());
                            //New Entity was created
                            //sendData(newPlayer.onCreate(this));
                            break;

            case "HND_SHK": System.out.println("[Server] Handshake Recieved");

                            String fdata = new String(p.getData());
                            String[] data = fdata.split(";");

                            //Get client by client ID
                            S_Client c = ClientList.get(Integer.parseInt(data[1]));
                            c.setUsername(data[3]);
                            System.out.println("[Server] Set Client " + data[1] + "'s username to " + data[3]); 
                            //Now spawn the player
                            sendData(new Packet((byte)9, "PLR_SPW".getBytes(), ("CID;" + data[1] + ";X;" + SPAWN_COORD_X + ";Y;" + SPAWN_COORD_Y).getBytes()).getBytes());
                            break;
        }
    }

    public String[] byteArrayToStringArray(byte[] b) {
        String fdata = new String(b);
        return fdata.split(";");
    }

    public void createEntity(BaseEntity be) throws MethodNotOverridenException, IOException {
        int ID = IDGenerator.incrementAndGet();
        be.setEntID(ID);
        EntityMap.put(ID, be);
        sendData(be.onCreate(this));
    }

    public void sendData(byte[] sendData, InetAddress IP, int port) throws IOException {
        System.out.println("[Server] Send packet " + sendData[0] + " " + new String(Arrays.copyOfRange(sendData, 1, 8)));
        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IP, port);
        socket.send(sendPacket);
    }

    public void sendData(byte[] sendData) throws IOException {
        for (S_Client entry : ClientList) {
            sendData(sendData, entry.getIp(), entry.getPort());
        }
    }

    @Override
    public void run() {
        try {
            Init();
            Running();
        } catch (SocketException e) {
            System.err.println(e);
        } catch (IOException e) {
            System.err.println(e);
        }
    }
}

客户端:

package client;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.Vector;

import shared.BaseEntity;
import shared.Packet;
import shared.Player;

public class C_GameLoop {
    //How fast should the game update?
    private static final int TICKS_PER_SECOND = 25;
    //How many ticks should be skipped in order to run it at that speed?
    //If it runs faster, then the Render() will be called more often
    private static final int TICKS_TO_SKIP = 1000 / TICKS_PER_SECOND;
    //How many times should you skip rendering, if you have to?
    private static final int MAX_FRAMESKIP = 5;

    RenderCanvas rc;

    InetAddress ServerIP;
    private DatagramSocket socket;
    private int port;
    private boolean connectedToServer = false;
    private boolean waitForData = false;
    private String username = "Dummy";
    byte[] sendPacket;

    Vector<BaseEntity> RenderList;
    Player player;


    int fps = 0;

    public C_GameLoop(RenderCanvas rc){
        this.rc = rc;
        RenderList = new Vector<BaseEntity>();
    }


    public boolean Connect(InetAddress ServerIP, int port) throws IOException {
        this.port = port;
        this.ServerIP = ServerIP;
        socket = new DatagramSocket();
        socket.setSoTimeout(4000);

        DatagramPacket recieveData = new DatagramPacket(new byte[1024], new byte[1024].length);

        System.out.println("[Client] Connecting to: " + ServerIP.getHostAddress() + ":" + port);
        //Send a login request
        sendData(new Packet((byte)1, "LGN_RQS".getBytes()).getBytes());
        int retries = 0;

        //Start the connect loop
            while(!connectedToServer) {
                try {
                    socket.receive(recieveData);
                    waitForData = false;
                    parseData(formatData(recieveData.getData()));
                    //recieveData.setData(new Packet((byte)0, new byte[0], new byte[0]).getBytes());
                } catch (SocketTimeoutException e) {
                    if(waitForData = true && retries <= 4) {
                        System.out.println("[Client] Failed to recieve response from server, retrying");
                        parseData(formatData(recieveData.getData()));
                        retries++;
                    } else {
                        System.out.println("[Client] Failed to Connect to the server!");
                        return false;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        return true;
    }

    public void sendData(byte[] data) throws IOException {
        System.out.println("[Client] Sent packet " + data[0] + " " + new String(Arrays.copyOfRange(data, 1, 8)));
        DatagramPacket sendPacket = new DatagramPacket(data, data.length, ServerIP, port);
        socket.send(sendPacket);
        waitForData = true;
    }

    private void parseData(Packet p) throws IOException {
        switch (p.getTagAsString()) {
            case "LGN_ACP": System.out.println("[Client] Login Accepted");
                            //Get the data needed to create a new player from the packet
                            String fdata = new String(p.getData());
                            String[] data = fdata.split(";");
                            Player player = new Player(Integer.parseInt(data[1]), Integer.parseInt(data[3].trim()));
                            //Add it to the render list
                            this.player = player;
                            rc.getCamera().addDrawableEntity(player);

                            System.out.println("[Client] Player created with CID " + data[1] + " and EID " + data[3]);

                            //Send the handshake
                            System.out.println("[Client] Finshing Handshake...");
                            sendData(new Packet((byte)4, "HND_SHK".getBytes(), ("CID;" + player.getCID() + ";Username;" + username).getBytes()).getBytes());
                            break;
            case "PLR_SPW": System.out.println("[Client] Spawn Recieved");
                            //Get the coords
                            String[] spawn_data = byteArrayToStringArray(p.getData());
                            this.player.setX(Integer.parseInt(spawn_data[3]));
                            this.player.setY(Integer.parseInt(spawn_data[5].trim()));

                            sendData(new Packet((byte)0, "KEP_ALV".getBytes()).getBytes());
                            break;

        }
    }

    public String[] byteArrayToStringArray(byte[] b) {
        String fdata = new String(b);
        return fdata.split(";");
    } 

    /*
     * Formats data into a packet
     */
    public static Packet formatData(byte[] data) {
        try {
            if(data[1] == 0);
            String tag = new String(Arrays.copyOfRange(data, 1, 8));
            System.out.println("[Client] Recieved packet " + data[0] + " " + new String(tag));
            return new Packet(data[0],tag.getBytes(), Arrays.copyOfRange(data, 8, data.length));
        } catch (ArrayIndexOutOfBoundsException e) {
            return new Packet((byte)0, new byte[0], new byte[0]);
        }
    }
}

运行代码时的控制台输出:

 INIT
[Server] Create listen server on 0.0.0.0 on port 4334
S_GameLoop staring
[Client] Connecting to: 127.0.0.1:4334
[Client] Sent packet 1 LGN_RQS
[Server] Recieved packet 1 LGN_RQS
[Server] Login Request Recieved
[Server] Created new Player with EID 0 and CID 0
[Server] Send packet 2 LGN_ACP
[Client] Recieved packet 2 LGN_ACP
[Client] Login Accepted
[Client] Player created with CID 0 and EID 0
[Client] Finshing Handshake...
[Client] Sent packet 4 HND_SHK
[Client] Failed to recieve response from server, retrying
(Same lines as previous 6 just repeat 4 times)
[Client] Failed to Connect to the server!

任何想法?

1 个答案:

答案 0 :(得分:1)

看起来您的Server类被设计为用作某个工作线程的Runnable

我怀疑问题是run()方法由于未捕获的异常而死亡,并且工作线程正在终止。

我建议您配置默认的未捕获异常处理程序,以(至少)记录致命异常的堆栈跟踪。有关详细信息,请参阅Thread javadoc。