Esk*_*ola 22 java sockets monitoring netty
我正在编写一个端到端测试,我的Java程序发布了它的所有资源 - 线程,服务器套接字,客户端套接字.它是一个库,因此通过退出JVM释放资源不是一种选择.测试线程的释放很容易,因为您可以向ThreadGroup询问其中的所有线程,但我还没有找到一种获取当前JVM正在使用的所有网络套接字列表的好方法.
有没有办法从JVM获取所有客户端和服务器套接字的列表,类似于netstat?我在Java 7上使用Netty和OIO(即java.net.ServerSocket和java.net.Socket).该解决方案需要在Windows和Linux上运行.
我的第一个偏好是使用纯Java从JVM中询问它.我试图寻找一个MX Bean或类似的,但没有找到任何.
另一个选择可能是连接到JVM的分析/调试API并询问Socket和ServerSocket的所有实例,但我不知道如何做到这一点以及是否可以在没有本机代码的情况下完成(AFAIK,JVMTI仅限本机) ).此外,它不应该使测试变慢(即使我最慢的端到端测试只有0.5秒,其中包括启动另一个JVM进程).
如果询问JVM不起作用,第三种选择是创建一个设计,在设置时跟踪所有套接字.这样做的缺点是可能会遗漏一些创建套接字的地方.由于我使用Netty,它似乎可以通过包装ChannelFactory和使用ChannelGroup来实现.
Esk*_*ola 16
我可以挂接到java.net.Socket和java.net.ServerSocket窥探所有这些类的新实例.可以在源存储库中看到完整的代码.以下是该方法的概述:
当实例化Socket或ServerSocket时,其构造函数中的第一件事是调用setImpl()实例化实际实现套接字功能的对象.默认实现是一个实例java.net.SocksSocketImpl,但可以通过设置自定义java.net.SocketImplFactory通过java.net.Socket#setSocketImplFactory和覆盖它java.net.ServerSocket#setSocketFactory.
所有的java.net.SocketImpl包私有实现都有点复杂,但有一些反思并不太难:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
在创建时监视所有套接字的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;
}
});
Run Code Online (Sandbox Code Playgroud)
请注意,setSocketFactory/setSocketImplFactory只能被调用一次,因此您需要只有一个测试(就像我拥有它),或者您必须创建一个静态单例(yuck!)来保存该间谍.
那么问题是如何找出套接字是否已关闭?Socket和ServerSocket都有一个方法isClosed(),但它使用这些类的布尔内部来跟踪它是否被关闭 - SocketImpl实例没有一种简单的方法来检查它是否被关闭.(顺便说一下,Socket和ServerSocket都有SocketImpl支持 - 没有"ServerSocketImpl".)
值得庆幸的是,SocketImpl引用了它支持的Socket或ServerSocket.前面提到的setImpl()方法调用impl.setSocket(this)or impl.setServerSocket(this),并且可以通过调用java.net.SocketImpl#getSocket或返回该引用java.net.SocketImpl#getServerSocket.
这些方法再次是包私有的,因此需要进行一些反思:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,可能不会在SocketImplFactory中调用getSocket/getServerSocket,因为Socket/ServerSocket仅在从那里返回SocketImpl之后才设置它们.
现在有了检查我们的测试所需的所有基础结构,无论我们想要什么关于Socket/ServerSocket:
for (SocketImpl impl : allSockets) {
assertIsClosed(getSocket(impl));
}
Run Code Online (Sandbox Code Playgroud)
完整的源代码在这里.
我自己没有尝试过,但JavaSpecialists时事通讯提出了类似的问题:
http://www.javaspecialists.eu/archive/Issue169.html
在底部,他描述了使用AspectJ的方法.您可以将切入点放在创建套接字的构造函数周围,并且具有在那里注册套接字创建的代码.
| 归档时间: |
|
| 查看次数: |
12302 次 |
| 最近记录: |