- A+
编写背景:
本人负责某银行的一个项目主力开发,在与第三方调试接口时遇到了一个问题:对方服务器明明给了我返回的值,但我这边却没有收到,日志中没有打印对应的值。一开始我认为是对方的问题,但是对方就丢了一句“我试了有的”,然后我就一个人风中凌乱。
随即我就想到了抓包的方式进行验证,看到底是哪一方的问题导致的。因为日志可能会骗人,但是抓包是不会的。
抓包的概念:
抓包顾名思义就是抓取数据包,基本上与第三方通讯就会产生数据包,我们将这些包做了一个抓取的动作,将它保存在我们指定的文件中。我们与第三方的交互走的是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; } }