編寫背景: 本人負責某銀行的一個項目主力開發,在與第三方調試介面時遇到了一個問題:對方伺服器明明給了我返回的值,但我這邊卻沒有收到,日誌中沒有列印對應的值。一開始我認為是對方的問題,但是對方就丟了一句“我試了有的”,然後我就一個人風中凌亂。 隨即我就想到了抓包的方式進行驗證,看到底是哪一方的問題導致 ...
編寫背景:
本人負責某銀行的一個項目主力開發,在與第三方調試介面時遇到了一個問題:對方伺服器明明給了我返回的值,但我這邊卻沒有收到,日誌中沒有列印對應的值。一開始我認為是對方的問題,但是對方就丟了一句“我試了有的”,然後我就一個人風中凌亂。
隨即我就想到了抓包的方式進行驗證,看到底是哪一方的問題導致的。因為日誌可能會騙人,但是抓包是不會的。
抓包的概念:
抓包顧名思義就是抓取數據包,基本上與第三方通訊就會產生數據包,我們將這些包做了一個抓取的動作,將它保存在我們指定的文件中。我們與第三方的交互走的是TCP,且無加密,所以我們只需要簡簡單單的抓包解析數據即可。
抓包前的準備:
首先要想在伺服器中使用抓包指令就需要安裝對應的抓包工具“tcpdump”,大部分伺服器上是沒有的,需要自行安裝,只有安裝了之後才能使用tcpdump的指令,安裝的教程直接百度搜一下“tcpdump安裝”即可。
準備好測試的數據,因為抓包的速度非常快,而且抓的東西也比較多,如果你的伺服器有其他應用去交互,可能會因為你的數據準備不充足導致你執行了抓包指令後大半天做不完交易,到時候抓出來的包非常笨重,且不方便查看。我的建議是自己估摸好發交易的節點,在節點前一步再執行抓包指令。
下載一個叫做Wireshark工具,這個工具專門用來解析抓包後的文件,工具的安裝及使用教程就自己百度了。
要得到伺服器的ROOT用戶密碼,因為tcpdump指令只能是root用戶下操作。
開始抓包:
1、登錄伺服器,使用root用戶;
2、在發起交易的前一步就要執行抓包指令;
3、在任意目錄下執行 tcpdump -i any -XO -vvv -s0 -w /root/anyport.cap
root/anyport.cap 這個是文件保存的路徑,可以自己定義。
4、執行完交易後,馬上在伺服器按CTRL+C停止抓包,否則會無限抓包,這個十分重要一定要牢記;
解析數據包:
1、在伺服器路徑中取出剛抓包的文件;
2、將文件丟進Wireshark工具中;
3、在工具上方的輸入框中輸入ip.addr=xxx.xxx.xxx.xx 可以直接定位對方ip地址的數據;
4、找到對方返回的報文內容;
5、很驚奇的發現居然是亂碼,這個其實是和內容編碼有關係,如果編碼是UTF-8之類的常見編碼則可以正常解析出來,但是項目採用的是cp937這類編碼,則就需要進行轉換了。如果你的解析沒有亂碼,下麵的內容對你意義不大了。
6、複製返回報文的hex值,選擇 hex stream;
7、在java中寫一個轉換的方法,對數據進行轉換。具體代碼我附上,解釋在代碼中註解;
package test; import java.io.UnsupportedEncodingException; public class test { public static void main(String[] args) throws UnsupportedEncodingException { /*將抓包到的hex值粘貼進來*/ byte[] teststr=hexToByteArray("40f0f5f7f44040f0f0f0f4f5f040404040404040404040404040404040f0f0f0f0404040404040f0f0f3f0f0f5f0f0f2f3f3f5f0f0f9f9f9f9f0f7f7f0f7f9f0f0f0f0f0f0f0f0f0404040404040404040f0f0f640f0f0f0f0f0f0f0f0f0f1f0f0f0f0f0f0f0f0f0f0f0f0f0f0f04040404040404040404040404040404040f0f3404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040d4c1c3c1e440c2d6c340e3c5e2e340c1c3c3d6e4d5e34040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040f1f3f8"); System.err.println(new String(teststr,"cp937"));//指定對應的編碼轉String } /** * Hex字元串轉byte * @param inHex 待轉換的Hex字元串 * @return 轉換後的byte */ public static byte hexToByte(String inHex){ return (byte)Integer.parseInt(inHex,16); } public static byte[] hexToByteArray(String inHex){ int hexlen = inHex.length(); byte[] result; if (hexlen % 2 == 1){ //奇數 hexlen++; result = new byte[(hexlen/2)]; inHex="0"+inHex; }else { //偶數 result = new byte[(hexlen/2)]; } int j=0; for (int i = 0; i < hexlen; i+=2){ result[j]=hexToByte(inHex.substring(i,i+2)); j++; } return result; } }