jjzjj

java - 找出当前 Java VM 中打开了哪些网络套接字

coder 2023-05-18 原文

我正在编写一个端到端测试,我的 Java 程序会释放其所有资源 - 线程、服务器套接字、客户端套接字。它是一个库,因此不能通过退出 JVM 来释放资源。 Testing the releasing of threads 很简单,因为你可以向 ThreadGroup 查询其中的所有线程,但是我还没有找到一个很好的方法来获取当前 JVM 正在使用的所有网络套接字的列表。

有什么方法可以从 JVM 获取所有客户端和服务器套接字的列表,类似于 netstat? 我在 Java 7 上使用 NettyOIO(即 java.net.ServerSocketjava.net.Socket )。解决方案需要同时在 Windows 和 Linux 上运行。

我的第一个偏好是使用纯 Java 从 JVM 询问它。我试图寻找 MX Bean 或类似的,但没有找到。

另一种选择可能是连接到 JVM 的分析/调试 API 并询问 Socket 和 ServerSocket 的所有实例,但我不知道该怎么做以及是否可以在没有 native 代码的情况下完成(AFAIK,JVMTI 是仅限 native )。此外,它不应该使测试变慢(即使我最慢的端到端测试也只有 0.5 秒,其中包括启动另一个 JVM 进程)。

如果询问 JVM 不起作用,第三种选择是创建一个在创建时跟踪所有套接字的设计。这样做的缺点是可能会丢失创建套接字的某些位置。由于我使用的是 Netty,它似乎可以通过包装 ChannelFactory 并使用 ChannelGroup 来实现。

最佳答案

我能够连接到 java.net.Socketjava.net.ServerSocket 并窥探这些类的 all 新实例。完整代码可见in the source repository .以下是该方法的概述:

当一个 Socket 或 ServerSocket 被实例化时,它的构造函数中的第一件事就是调用 setImpl() 来实例化真正实现套接字功能的对象。默认实现是 java.net.SocksSocketImpl 的一个实例,但可以通过设置自定义 java.net.SocketImplFactory 来覆盖它。通过java.net.Socket#setSocketImplFactoryjava.net.ServerSocket#setSocketFactory .

java.net.SocketImpl 的所有实现都使这有点复杂。是包私有(private)的,但有一点反射并不难:

private static SocketImpl newSocketImpl() {
    try {
        Class<?> defaultSocketImpl = Class.forName("java.net.SocksSocketImpl");
        Constructor<?> constructor = defaultSocketImpl.getDeclaredConstructor();
        constructor.setAccessible(true);
        return (SocketImpl) constructor.newInstance();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

用于在所有套接字创建时监视它们的 SocketImplFactory 实现如下所示:

    final List<SocketImpl> allSockets = Collections.synchronizedList(new ArrayList<SocketImpl>());
    ServerSocket.setSocketFactory(new SocketImplFactory() {
        public SocketImpl createSocketImpl() {
            SocketImpl socket = newSocketImpl();
            allSockets.add(socket);
            return socket;
        }
    });

请注意,setSocketFactory/setSocketImplFactory 只能调用一次,因此您要么只需要一个测试来执行此操作(就像我拥有的​​那样),要么您必须创建一个静态单例(糟糕!)来保存该 spy 。

那么问题来了,那如何判断socket是否关闭呢? Socket 和 ServerSocket 都有一个方法 isClosed(),但它使用这些类内部的 boolean 值来跟踪它是否已关闭 - SocketImpl 实例没有简单的方法来检查它是否已关闭关闭。 (顺便说一句,Socket 和 ServerSocket 都由 SocketImpl 支持 - 没有“ServerSocketImpl”。)

谢天谢地,SocketImpl 引用了它所支持的 Socket 或 ServerSocket。前面提到的 setImpl() 方法调用 impl.setSocket(this)impl.setServerSocket(this),并且可以取回那个引用通过调用 java.net.SocketImpl#getSocketjava.net.SocketImpl#getServerSocket

再一次,这些方法是包私有(private)的,所以需要一点反射(reflection):

private static Socket getSocket(SocketImpl impl) {
    try {
        Method getSocket = SocketImpl.class.getDeclaredMethod("getSocket");
        getSocket.setAccessible(true);
        return (Socket) getSocket.invoke(impl);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

private static ServerSocket getServerSocket(SocketImpl impl) {
    try {
        Method getServerSocket = SocketImpl.class.getDeclaredMethod("getServerSocket");
        getServerSocket.setAccessible(true);
        return (ServerSocket) getServerSocket.invoke(impl);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

注意getSocket/getServerSocket不能在SocketImplFactory内部调用,因为Socket/ServerSocket只有在SocketImpl从那里返回后才会设置它们。

现在有了所有必要的基础设施来检查我们的测试,无论我们想要什么 Socket/ServerSocket:

    for (SocketImpl impl : allSockets) {
        assertIsClosed(getSocket(impl));
    }

完整的源代码是here .

关于java - 找出当前 Java VM 中打开了哪些网络套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11669554/

有关java - 找出当前 Java VM 中打开了哪些网络套接字的更多相关文章

  1. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  2. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  3. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  4. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  5. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  6. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  7. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  8. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  9. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  10. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

随机推荐