alagris
alagris

Reputation: 2206

UDP client gets only beginning of data (Java)

I made a client and server that use UDP protocol. I know that UDP is not very reliable and data can get lost but I run everything on my local host and the size of data that i send is only about 10 bytes. The problem is that when server sends 4 bytes client receives only the first byte but when server sends 50 or 1000 bytes client receives... only first byte of data?! Yeah, exactly 1 byte (sometimes 2 or 3 but no more)! I have no idea whats going on. Is there an error in my code or this is fault of UDP?

Here is code of client

public void connect(String ip, int port) {
        try {
            adress = InetAddress.getByName(ip);
        } catch (UnknownHostException e) {
            error("UnknownHostException");
            e.printStackTrace();
        }

        try {
            noErrors = true;
            socket = new DatagramSocket();
            socket.setSoTimeout(5000);
            socket.connect(adress, port);

            confirmation = new DatagramPacket(buf, buf.length, adress, port);
            packet = new DatagramPacket(buf, buf.length, adress, port);

            preapreConfirmation();
            logIn();

        } catch (SocketException e) {
            error("Cannot connect");
            e.printStackTrace();
        }

    }
private void logIn(){
    String s;

    while (noErrors) {// Sending request for connecting
        sendRequest("2");
        s = new String(packet.getData());
        if (s.contains("2")) { // Connection was accepted
            break;
        } else if (s.contains("1")) {// Connection was refused
            disconnect();
            error("Connection refused");
            break;
        }
    }

    while(noErrors){ //loding map data: name
        sendRequest("4"); // ask about world name
        s = new String(packet.getData());
        try {
            System.out.println(s+" BYTES:"+s.getBytes().length+" "+socket.getReceiveBufferSize());
        } catch (SocketException e) {
            e.printStackTrace();
        }
        if(s.startsWith("4")){//world name was given
            if( s.split("_").length>1){
                mapname = s.split("_")[1];
                break;
            }
        }
    }

    while (noErrors) { // loding map data: hash
        sendRequest("6"); // ask about world hash
        s = new String(packet.getData());
        if (s.startsWith("6")) {
            if (s.contains("h")) { // world hash was given
                maphash = parse(s, 1);
                break;
            }
        }
    }

    if(!noErrors)return;
    System.out.println(maphash+" ==> "+ Screen.game.getHash(mapname)+" ("+mapname+")");
    if (Screen.game.checkIfWorldExists(maphash, mapname)) { //validating world
        Screen.game.loadMap(mapname);
        Screen.setState(GameStates.GAME);
    } else {
        sendCommand("0");
    }

    isLogged = true;
}

public void sendRequest(){
    try {
        socket.send(packet);//Sending data
        try{
            socket.receive(packet);//receiving answer
        } catch(PortUnreachableException ee){
            error("Cannot connect");
        } catch(SocketTimeoutException e){
            error("End of stream");
        }
        socket.send(confirmation);//Sending confirmation of receiving answer
    } catch (IOException e) {
        error("IOException");
        e.printStackTrace();
    }

}

private void error(String message){
    noErrors = false;
    Screen.setErrorState(message);
}

public void sendCommand(){
    try {
        socket.send(packet);
    } catch (IOException e) {
        e.printStackTrace();
    }

}

and here is code of server:

public void run() {

    System.out.println("Server is waiting for data from socket");

    while (isRunning) {
        try {
            buf = new byte[256];

            // receives request
            DatagramPacket packet = new DatagramPacket(buf, buf.length);

            socket.receive(packet);
            System.out.println("packet received");

            // creating response
            setCommand(new String(packet.getData(), "UTF-8"));

            String d = getNextQuote(getCommand());
            // sends the response to the client. "address" and "port" are
            // already saved in last received packet
            InetAddress address = packet.getAddress();
            int port = packet.getPort();
            System.out.println(">"+getCommand()+"\n<"+d);

            if(d.equals("7")){
                for(String g:packages){
                    buf = g.getBytes();
                    packet = new DatagramPacket(buf, buf.length, address, port);
                    socket.send(packet);
                }
            } else {
                buf = d.getBytes();
                packet = new DatagramPacket(buf, buf.length, address, port);
                socket.send(packet);
            }

        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
        }
    }
    System.err.println("Server stopped");
    socket.close();
}

In my code i use commands that make the size of sent data smaller so client and server can communicate using only one byte like for e.g. client sends: 1 - disconnect me 2 - connect me 3 - send map length (chunks quantity) 4 - send map name to me but then server must respond: 4_mapname and 1 byte is not enough

Upvotes: 1

Views: 449

Answers (1)

user207421
user207421

Reputation: 310957

You need to reset the length of the DatagramPacket before receiving.

And I'm not crazy about this:

confirmation = new DatagramPacket(buf, buf.length, adress, port);
packet = new DatagramPacket(buf, buf.length, adress, port);

Two DatagramPackets sharing the same data buffer. You'll need to be very careful how you use them. It would probably better to only have one, then you know you have to be careful. In fact when sending confirmations or replies of any kind it's better to re-use the packet containing the request you're replying to. That way the target address and port are already set, and all you have to do is set up the data, offset, and length.

Upvotes: 2

Related Questions