java - UDP 客户端仅获取数据的开头 (Java)

标签 java sockets udp limit

我做了一个使用UDP协议(protocol)的客户端和服务器。我知道 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 - 发送 map 长度( block 数量) 4 - 将 map 名称发送给我 但服务器必须响应:4_mapname 和 1 个字节不够

最佳答案

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

我对此并不疯狂:

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

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

关于java - UDP 客户端仅获取数据的开头 (Java),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25086222/

相关文章:

sockets - Haskell句柄的非阻塞关闭

udp - 最可靠,最有效的udp数据包大小?

python:调用 socket.recvfrom() 两次

java - 客户端/服务器应用程序中的 UDP

java - 检查 java 集合列表中包含的值

php:如何保存客户端套接字(未关闭),以便进一步的脚本可以检索它以发送答案?

java - spring 3 带文件上传的自动表单字段验证

c - 缓冲服务器 C

java 错误 IOException

java - 图像资源在 Android 中给出 0