UDP客户端只获取数据的开头(Java)

时间:2014-08-01 18:13:05

标签: java sockets udp limit

我制作了一个使用UDP协议的客户端和服务器。我知道UDP不是很可靠,数据可能会丢失,但我在本地主机上运行所有内容,我发送的数据大小只有10个字节。 问题是,当服务器发送4个字节时,客户端只接收第一个字节但服务器发送时 50或1000字节的客户端只接收数据的第一个字节?!是的,正好是1个字节(有时2或3但不多)!我不知道是怎么回事。我的代码中是否有错误或这是UDP的错误?

这是客户端代码

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();
    }

}

这是服务器的代码:

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();
}

在我的代码中,我使用的命令使发送数据的大小变小,因此客户端和服务器只能使用一个字节进行通信,例如客户发送: 1 - 断开我的联系 2 - 联系我 3 - 发送地图长度(块数量) 4 - 发送地图名称给我 但是服务器必须响应:4_mapname和1个字节是不够的

1 个答案:

答案 0 :(得分:2)

您需要在接收之前重置DatagramPacket的长度。

我并不为此疯狂:

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

两个DatagramPackets共享相同的数据缓冲区。您使用它们时需要非常小心。最好只有一个,然后你知道你必须要小心。实际上,在发送任何类型的确认或回复时,最好重新使用包含您回复的请求的数据包。这样,目标地址和端口已经设置好了,您所要做的就是设置数据,偏移量和长度。