客户端正在接收服务器的响应两次

时间:2014-08-15 00:48:32

标签: java networking udp

所以我正在研究java udp客户端和服务器,但客户端不断接收不正确的数据或双倍。这是我的代码。

public class Server extends Thread {  

static int playerx = 50;
static int playery = 50;
private DatagramSocket socket;
Player p;
Vector<Player> connectedPlayers = new Vector<Player>();

public static enum PacketTypes {
    INVALID(-1), LOGIN(00), DISCONNECT(01), MOVE(02);

    private int packetId;

    private PacketTypes(int packetId) {
        this.packetId = packetId;
    }

    public int getId() {
        return packetId;
    }
}

public byte packetId;

public static void main(String[] args){
    Server s = new Server();
    s.start();
}

public Server() {
    try {
        this.socket = new DatagramSocket(1331);
    } catch (SocketException e) {
        e.printStackTrace();
    }
}

public void run() {
    while (true) {
        byte[] data = new byte[1024];
        DatagramPacket packet = new DatagramPacket(data, data.length);
        try {
            socket.receive(packet);
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
    }
}

private void parsePacket(byte[] data, InetAddress address, int port) {
    String message = new String(data).trim();
    //System.out.println("Data: "+message);
    if(message.startsWith("00")){
        System.out.println("User Connected: "+message.substring(2, message.length()));
        p = new Player(50, 50, 1);
        sendData(("00"+p.x+"").getBytes(), address, port);
        sendData(("00"+p.y+"").getBytes(), address, port);
        System.out.println("LOGIN: "+ p.x+" || "+p.y);
        return;
    }
    if(message.startsWith("02")){
        //if(message.substring(2, message.length())=="R"){
            p.x+=1;
            System.out.println(p.x+" has increased again!");
            sendData(("02"+p.x+"").getBytes(), address, port);
            sendData(("02"+p.y+"").getBytes(), address, port);
            System.out.println("MOVE: "+p.x+" || "+p.y);
        //}
            return;
    }
}

public void sendData(byte[] data, InetAddress ipAddress, int port) {

        DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, port);
        try {
            this.socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
        }
}

}

游戏客户端是:

public class Game extends BasicGame{

Client c;

 public Game(String title) {
    super(title);
}

public static void main(String[] args){
    try {
        AppGameContainer app = new AppGameContainer(new Game("NET-CODE"));
        app.setDisplayMode(800, 600, false);
        app.setTargetFrameRate(60);
        app.start();
    } catch (SlickException e) {
        e.printStackTrace();
    }

    }

public boolean isCon = false;
public int x;
public int y;

@Override
public void render(GameContainer gc, Graphics g) throws SlickException {
    if(isCon){
        g.fillRect(x, y, 32, 32);
    }
}

@Override
public void init(GameContainer gc) throws SlickException {
    c = new Client("127.0.0.1", this);
    c.start();
    c.sendData("00James".getBytes());
}

@Override
public void update(GameContainer gc, int delta) throws SlickException {
    Input i = gc.getInput();
    if(i.isKeyDown(Input.KEY_D)){
        c.sendData("02R".getBytes());
    }
}

}

,客户端线程是:

public class Client extends Thread{

private InetAddress ipAddress;
private DatagramSocket socket;
private Game game;



public Client(String ipAddress, Game game) {
    try {
        this.socket = new DatagramSocket();
        this.ipAddress = InetAddress.getByName(ipAddress);
        this.game = game;
    } catch (SocketException e) {
        e.printStackTrace();
    } catch (UnknownHostException e) {
        e.printStackTrace();
    }
}

public void run() {
    while (true) {
        byte[] data = new byte[1024];
        DatagramPacket packet = new DatagramPacket(data, data.length);
        try {
            socket.receive(packet);
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
    }
}

int cycle = 0;
private void parsePacket(byte[] data, InetAddress address, int port) {
    String message = new String(data).trim();
    if(message.startsWith("02")){
    if(cycle == 0){
        game.x = Integer.parseInt(message.substring(2, message.length()));
        System.out.println(" MOVE Data X: "+message);
        cycle++;
    }
    if(cycle == 1){
        game.y = Integer.parseInt(message.substring(2, message.length()));
        System.out.println("MOVE Data Y: "+message);
        cycle=0;
    }
    }
    if(message.startsWith("00")){
        if(cycle == 0){
            game.x = Integer.parseInt(message.substring(2, message.length()));
            System.out.println("LOGIN Data X: "+message);
            cycle++;
        }
        if(cycle == 1){
            game.y = Integer.parseInt(message.substring(2, message.length()));
            System.out.println("LOGIN Data Y: "+message);
            cycle=0;
            game.isCon = true;
        }
        }
}

public void sendData(byte[] data) {
        DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, 1331);
        try {
            socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

因此,当服务器在移动时发送更新的播放器的x和y线时,它会发送默认的x和y,然后发送更新的x和y。因此,当我按D向右移动时,客户端会得到一个响应(打印到控制台): 51,50(在x轴上递增) 50,50(默认) 并且它会继续这样做,所以玩家在屏幕上画画根本不会移动!

1 个答案:

答案 0 :(得分:0)

错误,这是UDP,您可以多次接收任何数据报。你可能在某个地方有一个错误,没有显示,导致你发送两次,但即使修复了你仍然可以得到重复,你需要防御它。序号是一个好的开始。

然而还有另一个问题:

this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort());

private void parsePacket(byte[] data, InetAddress address, int port)

此方法无法使用参数,因为您还需要传递数据包长度。我会改变它只是接受DatagramPacket本身作为唯一参数,但在其中需要注意getData(), getLength(),甚至可能getOffset(),以及源地址的东西。