引入:架構
上一篇文章主要分析JDWP層傳輸的數據包的格式,這篇文章咱們主要關注於JDWP層是如何傳輸的。jvm
分析:socket
傳輸的具體實現是根據各個JVM本身實現,可是他們有個共同點就是都是用C/C++實現的,而且都實現了jdwpTransport.h (和上篇同樣的這個文件)。實現根據咱們的知識能夠得知是以dll文件(或者Unix平臺下是so文件)的形式存在。由於咱們從前面瞭解到,JDWP層有Agent負責在數據包和JVMTI的函數調用之間轉換,因此瓜熟蒂落知道,傳輸層的DLL文件也一定會有一個onload方法,而且讓Agent啓動時候調用的。ide
分析1:Agent如何訪問VM環境呢?函數
答案是經過環境指針(environment pointer), 該指針會在onload()方法中返回給Agent.這個環境指針的定義以下:測試
struct _jdwpTransportEnv; #ifdef __cplusplus typedef _jdwpTransportEnv jdwpTransportEnv; ... struct _jdwpTransportEnv { const struct jdwpTransportNativeInterface_ *functions;
因此這裏能夠看出,環境指針本質就是拿到一組能夠訪問目標VM環境的native接口。spa
分析2:Agent啓動時調用的onload()方法。指針
當Target VM加載了Agent以後,JDWP會根據參數去加載具體的JDWP的實現,Sun 的 JDK 在 Windows 提供 socket 和 share memory 兩種傳輸方式,而在 Linux 上只有 socket 方式)。傳輸層實現的動態連接庫實現必須暴露 jdwpTransport_OnLoad 接口,來對傳輸層初始化。blog
該方法簽名以下:接口
JNIEXPORT jint JNICALL jdwpTransport_OnLoad(JavaVM *jvm, jdwpTransportCallback *callback, jint version, jdwpTransportEnv** env);
從這裏能夠看出_OnLoad方法須要下面幾個入參:
jvm: 它讓Agent經過GetJavaVM方法來獲取JVM信息。
callback:它是一個函數表的指針,傳輸層用它來進行內存的分配與釋放。
version:它讓Agent得到指望的JDWPTRANSPORT的版本。
而後返回值就是在第四個參數中,它就是咱們想要的環境指針。
若是傳輸層初始化成功,那麼_OnLoad方法就會返回JNI_OK,不然會返回對應的錯誤碼。
分析3:jdwpTransport支持的方法概覽。
由於jdwpTransport須要維繫着Debugger和Target VM之間的關係,因此它有許多方法。咱們從幾大類來看。
分類1:用於管理鏈接
管理鏈接的方法其主要做用是用於創建和關閉到Debugger的鏈接。
a. Attach.它主要用於關聯到Debugger,創建到Debugger之間的可信鏈路.
步驟1:鏈接到指定的地址
步驟2:鏈接成功,則經過交換 」JDWP-Handshake"來確保到Debugger的鏈接的確被創建。
/* 3 : Attach */ jdwpTransportError (JNICALL *Attach)(jdwpTransportEnv* env, const char* address, jlong attach_timeout, jlong handshake_timeout);
從這裏能夠看出,除了環境指針外,它須要下面3個參數:
address: Debugger的地址和端口
attach_timeout:設置鏈接超時值,單位毫秒。若是設爲0則說明永不超時。
handshake_timeout:設置握手超時值,單位毫秒。若是設爲0則說明永不超時。
b.StartListening.它主要用於讓傳輸器處於listen模式,這樣它就能夠監聽來自Debugger的鏈接了。
/* 4: StartListening */ jdwpTransportError (JNICALL *StartListening)(jdwpTransportEnv* env, const char* address, char** actual_address);
除環境指針外,它還須要1個參數:
address:Debugger的地址和端口
actualAddress:返回值,返回傳輸器從address參數得到的真實字符串形式的地址。
c.StopListening.它主要用於讓傳輸器離開listen模式,這樣它就再也不監聽來自Debugger的鏈接了。
/* 5: StopListening */ jdwpTransportError (JNICALL *StopListening)(jdwpTransportEnv* env);
d.Accept.它主要用於創建來自Debugger的鏈接。
/* 6: Accept */ jdwpTransportError (JNICALL *Accept)(jdwpTransportEnv* env, jlong accept_timeout, jlong handshake_timeout);
e.IsOpen.它用於測試Debugger的鏈接是否開着。
/* 7: IsOpen */ jboolean (JNICALL *IsOpen)(jdwpTransportEnv* env);
f.Close.它用於關閉到Debugger的鏈接。
/* 8: Close */ jdwpTransportError (JNICALL *Close)(jdwpTransportEnv* env);
分類2:用於讀來自Debugger的數據包和發送到Debugger的數據包。
a. ReadPacket. 它用於在鏈接開着的狀態,從Debugger讀取數據包。
/* 9: ReadPacket */ jdwpTransportError (JNICALL *ReadPacket)(jdwpTransportEnv* env, jdwpPacket *pkt);
須要注意的是,該方法只對數據包作長度校驗,而不作完整性校驗。
b.WritePacket.它用於在鏈接開着的狀態,往Debugger寫數據包。
/* 10: Write Packet */ jdwpTransportError (JNICALL *WritePacket)(jdwpTransportEnv* env, const jdwpPacket* pkt);
分類3:輔助功能。
a.GetLastError.它用於返回用字符串表示的上次錯誤。
/* 11: GetLastError */ jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env, char** error);
b.GetCapabilities.它用於返回JDWP傳輸器全部支持的能力。
/* 2 : Get Capabilities */ jdwpTransportError (JNICALL *GetCapabilities)(jdwpTransportEnv* env, JDWPTransportCapabilities *capabilities_ptr);
能力的啓用和禁用是經過一組位圖位來標示的。
整個傳輸器的架構以下: