下面的代码,
import java.io.*;
import java.net.*;
class DatagramServer {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(null);
socket.bind(new InetSocketAddress("127.0.0.1", 0));
System.out.println(socket.getLocalSocketAddress());
while (true) {
// I just need client's address to send back some data!
DatagramPacket packet = new DatagramPacket(new byte[0], 0);
socket.receive(packet);
System.out.println(packet.getSocketAddress());
}
}
}在Windows中,它会像预期的那样阻塞。
> java --version
java 11.0.8 2020-07-14 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.8+10-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.8+10-LTS, mixed mode)
> java DatagramServer在macOS中,它没有,并打印了一堆接收到的套接字地址。
$ java -version
openjdk version "11.0.14" 2022-01-18
OpenJDK Runtime Environment Temurin-11.0.14+9 (build 11.0.14+9)
OpenJDK 64-Bit Server VM Temurin-11.0.14+9 (build 11.0.14+9, mixed mode)
$ java DatagramServer
/127.0.0.1:61206
/0.0.0.0:15922
/0.0.0.0:15922
/0.0.0.0:15922
/0.0.0.0:15922
/0.0.0.0:15922
/0.0.0.0:15922
/0.0.0.0:15922
/0.0.0.0:0
/0.0.0.0:15922
/0.0.0.0:15922
/0.0.0.0:15922
/0.0.0.0:15922
/0.0.0.0:15922
...这是正常的吗?
发布于 2022-03-01 18:06:56
我们在MacOS中而不是在Windows上看到这些问题的原因是,DatagramSocket和DatagramPacket类依赖于用于套接字连接的特定于操作系统的JDK实现。由于底层实现依赖于操作系统,我们在Windows、macOS或任何基于Linux的环境中都会看到不同的问题。
在上述问题的上下文中,DatagramSocket对象正在等待DatagramPacket。代码创建一个带有空字节数组的DatagramPacket。当字节数组为空时,数据报数据包只是向服务器请求信息。当服务器读取了所有数据包时,while循环将终止。
为了从服务器获得响应,客户端创建一个“接收”包,并使用DatagramSocket接收方法接收来自服务器的答复。接收方法等待到指定给客户端的数据报数据包通过套接字。
请注意,如果服务器的回复以某种方式丢失,由于数据报模型的无保证策略,客户端将永远等待。通常,客户端设置一个定时器,这样它就不会永远等待回复,如果没有回复,那么定时器就会关闭,客户机就会重新发送。
因此,在这里,客户机可能会超时,然后重新绑定可能会失败,因此套接字处于未指定的状态。这将进一步绑定到操作系统选择的通配符地址,并且它会无限期地重复循环,而不会被阻止。
在MacOS中有一个已知的问题。目前在JDK (15+)的后期版本中修复了这个问题。
第1期:JDK-8235674 -重新绑定失败问题 甲骨文虫
链接中的信息(JEP for JDK-15):
在macOS和Linux上,调用新实现上的断开可能需要重新绑定基础套接字。这可能会导致重新绑定失败,并使基础套接字处于未指定的状态。而遗留实现可能已将套接字静默地保留在未指定的状态中。
示例中提供的Java版本是OpenJDK版本11.0.14和11.0.8。在JDK-15之前,如果重新绑定失败,则套接字将处于未指定的状态。当断开连接时,DatagramSocket仍然是绑定的,解除绑定的是close()方法。构造函数的默认行为是立即绑定套接字。
但是在这里,我们通过DatagramSocket(null)创建了一个未绑定的DatagramSocket(null)作为构造函数参数。当重新绑定失败时,套接字移动到未指定的状态时,该套接字很有可能将由操作系统分配,直到JVM进程退出为止。
问题2: JDK-8231259- DatagramChannel::断开重新绑定到通配符地址(macOS)和甲骨文虫的套接字
上述问题是固定在JDK-14。DatagramChannel绑定到特定的本地地址,连接,然后调用断开以解除关联。在macOS上,disconnect将套接字重新绑定到wildcard地址。如果该对象是使用no构造函数创建的,则得到一个未绑定的套接字,因此它返回通配符IP地址0.0.0.0。如果IP地址为0.0.0.0,则套接字将绑定到通配符地址,即内核选择的IP地址。0.0.0.0是一个non-routable元地址,用于指定无效、未知或不适用的目标(“无特定地址”位置持有者)。
使用链接: JDK 17:DatagramSocket 数据报客户端服务器 UDP回路
StackOverflow:DataGramSocket问题 本地地址0.0.0.0
发布于 2022-02-26 10:10:46
我认为@ your 207421是对的,它可能与您的本地配置有关。在我的macbook上,第一个print语句是唯一被执行的语句--之后,服务器阻塞。
再考虑一下,由于绑定到127.0.0.1,服务器应该只监听从本地机器发送的数据,而不是整个本地网络。快速搜索google无助于找到导致这种行为的潜在原因,但也许您可以尝试使用这样的命令来分析流量:
while true; do lsof -lnP +M -i4 | grep '<server-port>'; sleep 1; done
https://stackoverflow.com/questions/70999028
复制相似问题