博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JPDA 架构研究19 - JDI的连接模块
阅读量:7137 次
发布时间:2019-06-28

本文共 4809 字,大约阅读时间需要 16 分钟。

引入:

上文提到了JDI的Mirror机制,把整个目标虚拟机上的所有数据、类型、域、方法、事件、状态和资源,以及调试器发向目标虚拟机的事件请求等都映射成Mirror 对象。这里进一步讨论JDI的链接模块。

分析:

连接模块其主要目的是提供调试器(Debugger)到目标虚拟机(Target VM)之间的交互通道。

从连接的发起方来看:连接的发起方可以是调试器,也可以是目标虚拟机。

从连接的数量来看,一个调试器可以连接多个目标VM, 但是一个目标VM只可以连接一个调试器。

我们从调试器(Debugger)的角度,可以把连接分为主动连接和被动连接。

分类1:主动连接 (它表示调试器主动去连接Target VM)

又分两种情况:

a. 当Target VM还没启动时,则使用LaunchingConnector这种形式的连接器,它会启动目标VM并连接。

Step 1: 调试器调用 VirtualMachineManager 的 launchingConnectors()方法获取所有的LaunchingConnector的实例。

1
2
3
4
5
6
7
public 
List<LaunchingConnector> launchingConnectors()
  
{
    
ArrayList list = 
new 
ArrayList(
2
);
    
list.add(
new 
SocketLaunchingConnectorImpl(
this
));
    
list.add(
new 
SocketRawLaunchingConnectorImpl(
this
));
    
return 
list;
  
}

Step 2:根据传输方式或其他特征选择一个LaunchingConnector,调用其 launch() 方法启动并且连接目标虚拟机 。启动后,返回目标虚拟机的实例。

比如说,如果选用SocketLaunchingConnectorImpl,则它的launch()方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public 
VirtualMachine launch(Map<String, ? 
extends 
Connector.Argument> connectionArgs)
    
throws 
IOException, IllegalConnectorArgumentsException, VMStartException
  
{
    
getConnectionArguments(connectionArgs);
 
    
SocketListeningConnectorImpl listenConnector = 
new 
SocketListeningConnectorImpl(
      
virtualMachineManager());
    
Map args = listenConnector.defaultArguments();
    
((Connector.IntegerArgument)args.get(
"timeout"
)).setValue(
10000
);
    
String address = listenConnector.startListening(args);
 
    
String slash = System.getProperty(
"file.separator"
);
    
String execString = 
this
.fHome + slash + 
"bin" 
+ slash + 
this
.fLauncher;
 
    
execString = execString + 
" -Xdebug -Xnoagent -Djava.compiler=NONE"
;
    
execString = execString + 
" -Xrunjdwp:transport=dt_socket,address=" 
+ address + 
",server=n,suspend=" 
+ (
this
.fSuspend ? 
"y" 
"n"
);
 
    
if 
(
this
.fOptions != 
null
) {
      
execString = execString + 
" " 
this
.fOptions;
    
}
 
    
execString = execString + 
" " 
this
.fMain;
 
    
String[] cmdLine = DebugPlugin.parseArguments(execString);
    
Process proc = Runtime.getRuntime().exec(cmdLine);
    
try
    
{
      
virtualMachine = (VirtualMachineImpl)listenConnector.accept(args);
    
}
    
catch 
(InterruptedIOException localInterruptedIOException)
    
{
      
VirtualMachineImpl virtualMachine;
      
proc.destroy();
      
String message = NLS.bind(ConnectMessages.SocketLaunchingConnectorImpl_VM_did_not_connect_within_given_time___0__ms_1, 
        
new 
String[] { 
        
((Connector.IntegerArgument)args
        
.get(
"timeout"
)).value() });
      
throw 
new 
VMStartException(message, proc);
    
}
    
VirtualMachineImpl virtualMachine;
    
virtualMachine.setLaunchedProcess(proc);
    
return 
virtualMachine;
  
}

b.当Target VM已经启动时,则使用AttachingConnector这种形式的连接器,它会挂接到目标虚拟机上。

前提是,Target VM必须以以下方式启动  -agentlib:jdwp=transport=xxx,server=y 参数启动,并根据传输方式生成监听地址。

Step1:调试器启动,调用 VirtualMachineManager 的 attachingConnectors()  方法获取所有的AttachingConnector的实例。

1
2
3
4
5
 
public 
List<AttachingConnector> attachingConnectors()
  
{
    
ArrayList list = 
new 
ArrayList(
1
);
    
list.add(
new 
SocketAttachingConnectorImpl(
this
));
    
return 
list;

Step 2: 根据目标虚拟机采用的传输方式选择一个AttachingConnector,调用其 attach() 方法挂接到目标虚拟机上。完成连接后,返回目标虚拟机的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
public 
VirtualMachine attach(Map<String, ? 
extends 
Connector.Argument> connectionArgs)
    
throws 
IOException, IllegalConnectorArgumentsException
  
{
    
getConnectionArguments(connectionArgs);
    
Connection connection = 
null
;
    
try 
{
      
connection = ((SocketTransportImpl)
this
.fTransport).attach(
this
.fHostname, 
        
this
.fPort, 
this
.fTimeout, 0L);
    
catch 
(IllegalArgumentException e) {
      
List args = 
new 
ArrayList();
      
args.add(
"hostname"
);
      
args.add(
"port"
);
      
throw 
new 
IllegalConnectorArgumentsException(e.getMessage(), args);
    
}
    
return 
establishedConnection(connection);
  
}

分类2:被动连接(它表示Debugger被动地等待或者监听由Target VM发起的连接)

前提是,Target VM必须以以下方式启动  -agentlib:jdwp=transport=xxx,address=yyy 参数启动,并根据传输方式生成监听地址。

Step 1:调试器通过 VirtualMachineManager 的 listeningConnectors() 方法获取所有的ListeningConnector实例。

1
2
3
4
5
6
 
public 
List<ListeningConnector> listeningConnectors()
  
{
    
ArrayList list = 
new 
ArrayList(
1
);
    
list.add(
new 
SocketListeningConnectorImpl(
this
));
    
return 
list;
  
}

Step 2:调用ListeningConnector的 startListening() 方法让连接器进入监听状态。通过 accept() 方法通知连接器开始等待正确的入站链接,该方法将返回调试器正在监听的地址描述符;目标虚拟机会自动地 attach 到调试器上建立连接,然后返回目标虚拟机的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
public 
String startListening(Map<String, ? 
extends 
Connector.Argument> connectionArgs)
    
throws 
IOException, IllegalConnectorArgumentsException
  
{
    
getConnectionArguments(connectionArgs);
    
String result = 
null
;
    
try 
{
      
result = ((SocketTransportImpl)
this
.fTransport).startListening(
this
.fPort);
    
catch 
(IllegalArgumentException localIllegalArgumentException) {
      
throw 
new 
IllegalConnectorArgumentsException(
        
ConnectMessages.SocketListeningConnectorImpl_ListeningConnector_Socket_Port, 
        
"port"
);
    
}
    
return 
result;
  
}
本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1588011,如需转载请自行联系原作者
你可能感兴趣的文章
Windows完成端口 IOCP模型(一)
查看>>
修改roo的密码 虚拟机vmware8.04 Centos 6.3
查看>>
Struts2 注解
查看>>
有关xerosploit运行报错问题的有效解决方案
查看>>
ABP官方文档翻译 1.4 启动配置
查看>>
js框架简明
查看>>
Java volatile 关键字
查看>>
http 头信息详解
查看>>
文件复制
查看>>
ATS项目更新(4) 更新DLL到远程服务器
查看>>
mac 多显示器焦点快速切换
查看>>
第六周学习进度报告
查看>>
nginx发布静态网页
查看>>
Hadoop 面试题之一
查看>>
有关方法重载的实例(例4-10)
查看>>
用数组模拟邻接表
查看>>
**Git中的AutoCRLF与SafeCRLF换行符问题
查看>>
Android布局文件layout.xml的一些属性值
查看>>
三种new
查看>>
多项式与三角函数求导——BUAA OO 第一单元作业总结
查看>>