通过TCP码流识别编码

前几天和北京的MM在联调时候出现一个问题,下面就简述下整个问题的定位过程,其中有很多思想还是对定位问题很有帮助的。

 

      问题是这样的,我们是服务器,而MM那边是使用客户端手机进行交互,而双方约定好使用utf-8来编解码。但是在联调过程中,在解析中文时出现了乱码(?)所以经过初步判断可以认定是MM那边上送了GBK编码的中文,而服务端这边使用了UTF-8编码来解码,那自然出现乱码?(注意GBK编码的中文,使用UTF-8来解码时,通常会出现?,通过这个表面现象也可以初步判断一定问题)。而客户端的MM非常肯定的说上送的UTF-8编码的中文。完全有一种不到黄河心不死的感觉!没办法,看来得使用一些手段让MM屈服,让他现出原型。

 

    问题定位过程:我们知道数据是通过二进制流在网络中传输的,所以可以将码流通过抓包的方式抓到,然后tcpdump命令可以帮我们完成这个任务。

 

使用命令tcpdump -i eth0 tcp port <端口> -Xs 10000 -vv,抓到数据报如下

 

14:51:21.122716 IP (tos 0x0, ttl  51, id 25274, offset 0, flags [DF], length: 301) 221.130.33.135.23966 > pim2.pim.28080: P [tcp sum ok] 788:1037(249) ack 1 win 33516 <nop,nop,timestamp 1943931360 3385024464>

0x0000   4500 012d 62ba 4000 3306 3b3e dd82 2187        E..-b.@.3.;>..!.

0x0010   c0a8 e920 5d9e 6db0 c90d 5138 eadd b169        ....].m...Q8...i

0x0020   8018 82ec 86a2 0000 0101 080a 73de 09e0        ............s...

0x0030   c9c3 5fd0 789c a551 416a c330 10bc 17fa        .._.x..QAj.0....

0x0040   87e0 7b2b ed4a b215 5014 2826 e043 2f76        ..{+.J..P.(&.C/v

0x0050   fa00 9388 6088 e5b6 2ac1 e9eb bb9b 38b8        ....`...*.....8.

0x0060   507a 28bd 6867 6747 338b e4d6 637f 5c9c        Pz(.hggG3...c.\.

0x0070   c27b ea86 b8ca e051 668b 1077 c3be 8b87        .{.....Qf..w....

0x0080   55f6 b2dd 3cd8 6ced efef 5c19 cbf6 a3ad        U...<.l...\.....

0x0090   c31b 37cf e950 951e 9cb8 0266 da91 70d3        ..7..P.....f..p.

0x00a0   7d06 8f52 5b9a cc04 df0e 27d2 2953 60ae        }..R[.....'.)S`.

0x00b0   246a 6509 2d25 3a71 1db0 82dc b7e7 d7e0        $je.-%:q........

0x00c0   539f 88be 7534 791a 462e 9796 226f 74d3        S...u4y.F..."ot.

0x00d0   272e d59e 493a 5942 d920 25a0 82c2 2865        '...I:YB..%...(e

0x00e0   487c 517a 90b9 b100 da89 8689 da83 b245        H|Qz...........E

0x00f0   5e58 ad73 5ab5 664e 4c7e b32d feb0 5d02        ^X.sZ.fNL~.-..].

0x0100   d2f2 38db a241 2931 0765 0c82 253f f853        ..8..A)1.e..%?.S

0x0110   82fa 2541 ff33 a14a 9b2e b647 7f26 ff09        ..%A.3.J...G.&..

0x0120   f274 7a48 f1fd 2bbf 00db f77f 43               .tzH..+.....C

 

由于tcpdump抓到数据是IP数据报格式,所以必须理解IP数据报和TCP段格式才可以将里边真正的数据截取出来。IP数据报的长度是由第一个字节的低4位表示,也就是报文中的

0x0000   4500 012d 62ba 4000 3306 3b3e dd82 2187        E..-b.@.3.;>..!.,红色部分,由于IP数据报和TCP段格式都是以段为单位一个段是4字节,所以4 * 5表示IP数据报的长度是20字节,所以将IP数据报的数据去掉只剩下如下报文。、

 

5d9e 6db0 c90d 5138 eadd b169        ....].m...Q8...i

0x0020   8018 82ec 86a2 0000 0101 080a 73de 09e0        ............s...

0x0030   c9c3 5fd0 789c a551 416a c330 10bc 17fa        .._.x..QAj.0....

0x0040   87e0 7b2b ed4a b215 5014 2826 e043 2f76        ..{+.J..P.(&.C/v

0x0050   fa00 9388 6088 e5b6 2ac1 e9eb bb9b 38b8        ....`...*.....8.

0x0060   507a 28bd 6867 6747 338b e4d6 637f 5c9c        Pz(.hggG3...c.\.

0x0070   c27b ea86 b8ca e051 668b 1077 c3be 8b87        .{.....Qf..w....

0x0080   55f6 b2dd 3cd8 6ced efef 5c19 cbf6 a3ad        U...<.l...\.....

0x0090   c31b 37cf e950 951e 9cb8 0266 da91 70d3        ..7..P.....f..p.

0x00a0   7d06 8f52 5b9a cc04 df0e 27d2 2953 60ae        }..R[.....'.)S`.

0x00b0   246a 6509 2d25 3a71 1db0 82dc b7e7 d7e0        $je.-%:q........

0x00c0   539f 88be 7534 791a 462e 9796 226f 74d3        S...u4y.F..."ot.

0x00d0   272e d59e 493a 5942 d920 25a0 82c2 2865        '...I:YB..%...(e

0x00e0   487c 517a 90b9 b100 da89 8689 da83 b245        H|Qz...........E

0x00f0   5e58 ad73 5ab5 664e 4c7e b32d feb0 5d02        ^X.sZ.fNL~.-..].

0x0100   d2f2 38db a241 2931 0765 0c82 253f f853        ..8..A)1.e..%?.S

0x0110   82fa 2541 ff33 a14a 9b2e b647 7f26 ff09        ..%A.3.J...G.&..

0x0120   f274 7a48 f1fd 2bbf 00db f77f 43               .tzH..+.....C

 

剩下的报文有TCP段格式和真正的数据体构成,而TCP段格式的第13个字节的高4位代表整个TCP段格式的首部长度,也就是如下报文中的红色部分

                5d9e 6db0 c90d 5138 eadd b169        ....].m...Q8...i

0x0020   8018 82ec 86a2 0000 0101 080a 73de 09e0        ............s...

4 * 8=32,也就是TCP段格式的首部长度为32字节。

 

截取TCP段格式的数据剩下如下所示:

                   789c a551 416a c330 10bc 17fa        .._.x..QAj.0....

0x0040   87e0 7b2b ed4a b215 5014 2826 e043 2f76        ..{+.J..P.(&.C/v

0x0050   fa00 9388 6088 e5b6 2ac1 e9eb bb9b 38b8        ....`...*.....8.

0x0060   507a 28bd 6867 6747 338b e4d6 637f 5c9c        Pz(.hggG3...c.\.

0x0070   c27b ea86 b8ca e051 668b 1077 c3be 8b87        .{.....Qf..w....

0x0080   55f6 b2dd 3cd8 6ced efef 5c19 cbf6 a3ad        U...<.l...\.....

0x0090   c31b 37cf e950 951e 9cb8 0266 da91 70d3        ..7..P.....f..p.

0x00a0   7d06 8f52 5b9a cc04 df0e 27d2 2953 60ae        }..R[.....'.)S`.

0x00b0   246a 6509 2d25 3a71 1db0 82dc b7e7 d7e0        $je.-%:q........

0x00c0   539f 88be 7534 791a 462e 9796 226f 74d3        S...u4y.F..."ot.

0x00d0   272e d59e 493a 5942 d920 25a0 82c2 2865        '...I:YB..%...(e

0x00e0   487c 517a 90b9 b100 da89 8689 da83 b245        H|Qz...........E

0x00f0   5e58 ad73 5ab5 664e 4c7e b32d feb0 5d02        ^X.sZ.fNL~.-..].

0x0100   d2f2 38db a241 2931 0765 0c82 253f f853        ..8..A)1.e..%?.S

0x0110   82fa 2541 ff33 a14a 9b2e b647 7f26 ff09        ..%A.3.J...G.&..

0x0120   f274 7a48 f1fd 2bbf 00db f77f 43               .tzH..+.....C

 

这个就是我们真正的从客户端上送的数据,所以将他拿到后,由于是16进制的所以需要将这些数据转成byte数据,就可以使用他new String(b, "UTF-8"),来检验客户端上送的报文是否是UTF-8编码的,如果显示乱码那么就应该不是UTF-8编码的。

 

byte[] bb = new byte[]{(byte)0x78,(byte)0x9c,(byte)0xa5,(byte)0x51,(byte)0x41(byte)0x6a,(byte)0xc3,(byte)0x30,(byte)0x10,(byte)0xbc,(byte)0x17,(byte)0xfa,      

(byte)0x87,(byte)0xe0,(byte)0x7b,(byte)0x2b,(byte)0xed(byte)0x4a,(byte)0xb2,(byte)0x15,(byte)0x50,(byte)0x14,(byte)0x28,(byte)0x26,(byte)0xe0,(byte)0x43,(byte)0x2f,(byte)0x76,

(byte)0xfa,(byte)0x00,(byte)0x93,(byte)0x88,(byte)0x60(byte)0x88,(byte)0xe5,(byte)0xb6,(byte)0x2a,(byte)0xc1,(byte)0xe9,(byte)0xeb,(byte)0xbb,(byte)0x9b,(byte)0x38,(byte)0xb8,

(byte)0x50,(byte)0x7a,(byte)0x28,(byte)0xbd,(byte)0x68(byte)0x67,(byte)0x67,(byte)0x47,(byte)0x33,(byte)0x8b,(byte)0xe4,(byte)0xd6,(byte)0x63,(byte)0x7f,(byte)0x5c,(byte)0x9c,

(byte)0xc2,(byte)0x7b,(byte)0xea,(byte)0x86,(byte)0xb8(byte)0xca,(byte)0xe0,(byte)0x51,(byte)0x66,(byte)0x8b,(byte)0x10,(byte)0x77,(byte)0xc3,(byte)0xbe,(byte)0x8b,(byte)0x87,

(byte)0x55,(byte)0xf6,(byte)0xb2,(byte)0xdd,(byte)0x3c(byte)0xd8,(byte)0x6c,(byte)0xed,(byte)0xef,(byte)0xef,(byte)0x5c,(byte)0x19,(byte)0xcb,(byte)0xf6,(byte)0xa3,(byte)0xad,

(byte)0xc3,(byte)0x1b,(byte)0x37,(byte)0xcf,(byte)0xe9(byte)0x50,(byte)0x95,(byte)0x1e,(byte)0x9c,(byte)0xb8,(byte)0x02,(byte)0x66,(byte)0xda,(byte)0x91,(byte)0x70,(byte)0xd3,

(byte)0x7d,(byte)0x06,(byte)0x8f,(byte)0x52,(byte)0x5b(byte)0x9a,(byte)0xcc,(byte)0x04,(byte)0xdf,(byte)0x0e,(byte)0x27,(byte)0xd2,(byte)0x29,(byte)0x53,(byte)0x60,(byte)0xae,

(byte)0x24,(byte)0x6a,(byte)0x65,(byte)0x09,(byte)0x2d(byte)0x25,(byte)0x3a,(byte)0x71,(byte)0x1d,(byte)0xb0,(byte)0x82,(byte)0xdc,(byte)0xb7,(byte)0xe7,(byte)0xd7,(byte)0xe0,

(byte)0x53,(byte)0x9f,(byte)0x88,(byte)0xbe,(byte)0x75(byte)0x34,(byte)0x79,(byte)0x1a,(byte)0x46,(byte)0x2e,(byte)0x97,(byte)0x96,(byte)0x22,(byte)0x6f,(byte)0x74,(byte)0xd3,

(byte)0x27,(byte)0x2e,(byte)0xd5,(byte)0x9e,(byte)0x49(byte)0x3a,(byte)0x59,(byte)0x42,(byte)0xd9,(byte)0x20,(byte)0x25,(byte)0xa0,(byte)0x82,(byte)0xc2,(byte)0x28,(byte)0x65,

(byte)0x48,(byte)0x7c,(byte)0x51,(byte)0x7a,(byte)0x90(byte)0xb9,(byte)0xb1,(byte)0x00,(byte)0xda,(byte)0x89,(byte)0x86,(byte)0x89,(byte)0xda,(byte)0x83,(byte)0xb2,(byte)0x45,

(byte)0x5e,(byte)0x58,(byte)0xad,(byte)0x73,(byte)0x5a(byte)0xb5,(byte)0x66,(byte)0x4e,(byte)0x4c,(byte)0x7e,(byte)0xb3,(byte)0x2d,(byte)0xfe,(byte)0xb0,(byte)0x5d,(byte)0x02,

(byte)0xd2,(byte)0xf2,(byte)0x38,(byte)0xdb,(byte)0xa2(byte)0x41,(byte)0x29,(byte)0x31,(byte)0x07,(byte)0x65,(byte)0x0c,(byte)0x82,(byte)0x25,(byte)0x3f,(byte)0xf8,(byte)0x53,

(byte)0x82,(byte)0xfa,(byte)0x25,(byte)0x41,(byte)0xff(byte)0x33,(byte)0xa1,(byte)0x4a,(byte)0x9b,(byte)0x2e,(byte)0xb6,(byte)0x47,(byte)0x7f,(byte)0x26,(byte)0xff,(byte)0x09,

(byte)0xf2,(byte)0x74,(byte)0x7a,(byte)0x48,(byte)0xf1(byte)0xfd,(byte)0x2b,(byte)0xbf,(byte)0x00,(byte)0xdb,(byte)0xf7,(byte)0x7f,(byte)0x43};

        //该码流是被压缩过的所以要先解压

        byte[] aa = GzipUtility.unzip(bb);

       

        try

        {

            System.out.println(new String(aa, "UTF-8"));

        }

        catch (UnsupportedEncodingException e)

        {

            e.printStackTrace();

        }

 

输出结果:

<?xml version="1.0" encoding="UTF-8"?>

<DnDataReq>

<MsgID>1</MsgID>

<MaxMsgSize>2048</MaxMsgSize>

<DevID>35726302438572902</DevID>

<DataType>sms</DataType>

<Box>

<Type>1</Type>

<Sms>

<Id>1</Id>

<T>20100123175335</T>

<S>10658114</S>

<R>????</R>

</Sms>

<Sms>

<Id>2</Id>

<T>20100129120242</T>

<S>1252002613552187841</S>

<R>????</R>

</Sms>

<Sms>

<Id>3</Id>

<T>20100129120244</T>

<S>1252002613552187841</S>

<R>????</R>

</Sms>

<IsFinal>y</IsFinal>

</Box>

</DnDataReq>

 

而用GBK解码后,输出结果:

<?xml version="1.0" encoding="UTF-8"?>

<DnDataReq>

<MsgID>1</MsgID>

<MaxMsgSize>2048</MaxMsgSize>

<DevID>35726302438572902</DevID>

<DataType>sms</DataType>

<Box>

<Type>1</Type>

<Sms>

<Id>1</Id>

<T>20100123175335</T>

<S>10658114</S>

<R>内容</R>

</Sms>

<Sms>

<Id>2</Id>

<T>20100129120242</T>

<S>1252002613552187841</S>

<R>内容</R>

</Sms>

<Sms>

<Id>3</Id>

<T>20100129120244</T>

<S>1252002613552187841</S>

<R>内容</R>

</Sms>

<IsFinal>y</IsFinal>

</Box>

</DnDataReq>

 

MM终于在铁的事实面前屈服了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值