通過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終於在鐵的事實面前屈服了。
相關文章
- [java IO流]之編碼和解碼Java
- TCP/IP 通訊傳輸流TCP
- NPM酷庫040:jschardet,識別資料編碼NPMJS
- Java的識別符號與編碼規範Java符號
- storm 初識編碼ORM
- golang 通過docker 搭建 ocr識別GolangDocker
- 【譯】通過閱讀原始碼來提高 JS 知識原始碼JS
- 通過了解 Redux 簡單原始碼,掌握 Redux 資料流原理Redux原始碼
- 簡單驗證碼識別及工具編寫思路
- 高通程式碼編譯編譯
- 驗證碼識別
- ==和is的區別 以及編碼和解碼
- 使用darknet識別點選驗證碼詳細過程(附帶原始碼)原始碼
- Nginx通過域名代理tcp埠NginxTCP
- 通義靈碼——靈動指間,快碼加編,你的智慧編碼助手
- 通過在作業系統中實際操作,學習和理解 Unicode 編碼相關知識作業系統Unicode
- 初探驗證碼識別
- halcon識別二維碼
- playwright--自動化(二):過滑塊驗證碼 驗證碼缺口識別
- 使用 Eager Execution 編碼並執行圖表:以通過 RevNet 優化程式碼為例優化
- python 驗證碼識別示例(一) 某個網站驗證碼識別Python網站
- 通過編寫指令碼和程式來擴充套件SSIS包NZ指令碼套件
- 通義靈碼實踐教程——編碼使用實踐
- Dubbo原始碼分析(六)Dubbo通訊的編碼解碼機制原始碼
- liunx通過TCP傳送資訊TCP
- TCP/IP的通訊過程-VeCloudTCPCloud
- 汽車VIN碼識別,車架號識別SD
- Android視訊編碼和直播推流教程Android
- 急速入門前端編碼知識前端
- Flutter - 生成二維碼與識別二維碼Flutter
- 通過身份證號碼獲取人的年齡和性別
- Laravel——通過郵件找回密碼Laravel密碼
- 通過原始碼分析Mybatis的功能原始碼MyBatis
- 通過程式碼掛上物理頁
- 幹掉大小流切換 I 幀!阿里雲 RTC QoS 及視訊編碼聯合優化之切流編碼阿里優化
- 通過故事引申網路協議TCP協議TCP
- Android中使用ffmpeg編碼進行rtmp推流Android
- C#通過百度Ai介面實現圖片文字識別核心程式碼-楊麻子部落格C#AI