首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么DatagramSocket#receive(DatagramPacket)不使用macOS进行阻塞?

为什么DatagramSocket#receive(DatagramPacket)不使用macOS进行阻塞?
EN

Stack Overflow用户
提问于 2022-02-05 14:41:05
回答 2查看 325关注 0票数 1

下面的代码,

代码语言:javascript
复制
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中,它会像预期的那样阻塞。

代码语言:javascript
复制
> 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中,它没有,并打印了一堆接收到的套接字地址。

代码语言:javascript
复制
$ 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
...

这是正常的吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-03-01 18:06:56

我们在MacOS中而不是在Windows上看到这些问题的原因是,DatagramSocketDatagramPacket类依赖于用于套接字连接的特定于操作系统的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.1411.0.8。在JDK-15之前,如果重新绑定失败,则套接字将处于未指定的状态。当断开连接时,DatagramSocket仍然是绑定的,解除绑定的是close()方法。构造函数的默认行为是立即绑定套接字。

但是在这里,我们通过DatagramSocket(null)创建了一个未绑定的DatagramSocket(null)作为构造函数参数。当重新绑定失败时,套接字移动到未指定的状态时,该套接字很有可能将由操作系统分配,直到JVM进程退出为止。

问题2: JDK-8231259- DatagramChannel::断开重新绑定到通配符地址(macOS)和甲骨文虫的套接字

上述问题是固定在JDK-14DatagramChannel绑定到特定的本地地址,连接,然后调用断开以解除关联。在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

Fix:JDK-15修复 发行说明

票数 3
EN

Stack Overflow用户

发布于 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://security.stackexchange.com/a/17204

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70999028

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档