天天看點

銀聯ISO8583封包格式、組包和解包過程、TPDU、位圖計算

ISO8583

全面掌握ISO8583封包

最開始時,金融系統隻有IBM這些大的公司來提供裝置,象各種主機與終端等。在各個計算機裝置之間,需要交換資料。

我們知道資料是通過網絡來傳送的,而在網絡上傳送的資料都是基于0或1這樣的二進制資料,如果沒有對資料進行編碼,

則這些資料沒有人能夠了解,屬于沒有用的資料。起初的X.25、SDLC以及現在流行的TCP/IP網絡協定都提供底層的通訊編碼協定,

它們解決了最底層的通訊問題,能夠将一串字元從一個地方傳送到另一個地方。但是,僅僅傳送字元串是沒有太大意義的,

怎樣來解析字元串代表什麼内容是非常重要的,否則傳送一些“0123abcd”的字元串也是無用的亂碼。

讓我們随着時光回到幾十年前的某個時刻,假設我們被推到曆史的舞台上,由我們來設計一個通用封包協定,來解決金融系統之間的封包交

換,暫且稱該協定叫做ISO8583協定。此時,技術是在不斷的前行,當初IBM一支獨秀的局面好像已經不妙了,各種大小不一的公司都進入金

融行業以求能有所斬獲,呈一片百花齊放的局面。我們怎樣來設計一個封包協定,能夠将這些如雨後春筍般出現的所有公司都納入進來,其

實也不是一件很簡單的事。

我們還是先一步步的來考慮吧。金融行業其實涉及到的資料内容并不是成千上萬,無法統計,恰恰相反,是比較少的。我們都可以在心底數

得過來,象交易類型、帳号、帳戶類型、密碼、交易金額、交易手續費、日期時間、商戶代碼、2磁3磁資料、交易序列号等,把所有能夠總

結出來的都總結起來不過100個左右的資料。那我們可以首先簡單的設計ISO8583,定義128個字段,将所有能夠考慮到的類似上面提到的“帳

号”等金融資料類型,按照一個順序排起來,分别對應128個字段中的一個字段。每個資料類型占固定的長度,這個順序和長度我們都事先定

義好。這樣就簡單了,要發送一個封包時,就将128個字段按照順序接起來,然後将接起來的整串資料包發送出去。

任何金融軟體收到ISO8583包後,直接按照我們定義的規範解包即可,因為整個封包的128個字段從哪一位到哪一位代表什麼,大家都知道,

隻要知道你的資料包是ISO8583包即可,我們都已經定義好了。比如第1個字段是“交易類型”,長度為4位,第2個字段位是“帳号”,為19位

等等。接收方就可以先取4位,再取接着的19位,依次類推,直到整個資料包128個字段都解完為止。

其實這種做法真是簡單直接,基本上就可以滿足需要了。不過我們有幾個問題要思考下:

  1. 我怎麼知道每個字段的資料類型呢,是數字還是字元?
  2. 每個傳送的封包都把128個字段都傳過去,那網絡帶寬能夠承受得了,有時候我可能隻需要其中5個字段,結果多收到了123個無用的字段。
  3. 如果我某些字段的長度不固定,屬于變長怎麼辦,因為你現在解包是當作資料包每個字段都是固定的,用C語言解包時直接依靠指針取固定長度的一串字元做為一個字段。

我們來一一解決這些問題。

第一個問題簡單,我在定義ISO8583時除了定義每個字段表示什麼,還規定其内容是數字或是字元等即可。考慮可能出現的類型不過有以下

幾種:字母、數字、特殊字元、年月日等時間、二進制資料。比如我對128個字段中的“商戶類型”字段定義其長度是15,同時定義其類型為

字母。再精細點,如果“商戶類型”裡面的資料同時包括數字和字母呢?那我們就定義其類型為字母也可,為數字也可,即一個字段可以同時

屬于多個類型。

第二個問題稍微複雜點。其本質就是如果我隻傳128個字段的5個字段,接收方怎麼知道我傳了哪幾個字段給它了。要是我們把剩下的123全部

填成0或其他特殊辨別,标明該字段不需要使用?這種處理方法沒有半點用處,沒有解決網絡帶寬的本質問題,還是要傳128個字段。

換個思路,我在封包前面加上個標頭,標頭裡面包含的資訊能夠讓别人知道隻傳了5個字段。怎樣設計這個標頭,可以這樣,我們用16個位元組

,即128個bit(一個位元組等于8bit)來表示128個字段中的某個字段是否存在。每個bit在計算機的二進制裡面不是1就是0,如果是1就表示對

應的字段在本次封包中存在,如果是0就是不存在。這樣好了,如果别人接收到了ISO8583封包,可以先根據最前面的封包頭,就知道緊接着

封包頭後面的封包有哪些字段,沒有哪些字段了。比如,我要發送5個字段,分别屬于128個字段中的第2、3、6、8、9字段,我就可以将

128bit的封包頭填成011001011000000000…………,一共128個bit,後面就全是0了。注意其中第2、3、6、8、9位為1,其他都為0。

有了這個128bit的封包頭,我們就可以隻發送需要的5個字段了。怎樣組織封包?先放上這128bit,即16個位元組的頭,

然後在頭後面放2、3、6、8、9字段,這些字段緊挨在一起,3和6之間也不需要填上4、5這兩個字段了。接收方收到這個封包,

它會根據128bit的封包頭來解包,它自然知道把第3個字段取出後,就直接在第3字段的後面取第6個字段,每個字段的長度在ISO8583裡面都

定義好了,很輕松就把資料包解出來了。

這下好了,為了解決上面的第二問題,我們隻是在封包中增加了16個位元組的資料,就輕松搞定了,我們把這16個位元組稱為bit map,即位圖,

用來表示某個位是否存在。不過我們再稍微優化一下,考慮到很多時候封包不需要128個字段這麼多,其一半64個字段都不一定能夠用完。

那我可以将封包頭由128bit減到64bit,隻有在需要的時候才把剩下的64bit放到封包裡面,這樣封包長度不又少了8個位元組嗎?

是個好主意。我們把ISO8583的128個字段中最常見的都放到前64個字段中,那我們可以将處理縮小一倍。這樣我一般發送封包時隻需

發送64bit,即一個位元組的封包頭,再加上需要的幾個字段就可以了。如果有些封包用到64到128之間的字段呢?這個也好辦,我把64bit封包

頭的第一位bit用來代表特殊含義,如果該bit為1,則表示64bit後面跟了剩下的64bit封包頭;如果第一位bit為0,則表示64bit後面沒有跟

剩下的64bit封包頭,直接是128個字段中的封包了。那們,接收方會判斷一下報頭的第一個bit是1還是0,進而知道封包頭是

64bit還是128bit了,就可以做相應處理。因為封包頭第二個64bit屬于有時候有,是以我們叫它Extended bit map擴充位圖,

相應的封包頭最開始的64bit我們叫它Primary bit map主位圖。我們直接把擴充位圖固定放到128個字段的第一個字段,

而主位圖每個資料包都有,就強制性放在所有128個字段的前面,并不歸入128個字段中去。

第三個問題可以考慮這樣解決。比如第2個字段是“帳号”,是不定長的,可能有的銀行帳号是19位,有的是17位等。

我們定ISO8583規範時可以規定第2個字段是25位,這下足夠将19和17的情況都包含進來,但是如果以後出現了30位的怎麼辦?

那我們現在将字段定為100位。以後超過100位怎麼辦,況且如果你隻有19位的帳号,我們定義了100位,

那81位的資料不是浪費了網絡的帶寬。看來預先定義一個我們認為比較大的位數是不太好的。

我們這樣,對于第2個字段“帳号”,在字段的開頭加上“帳号”的長度。比如帳号是0123456789,一共10位,我們變成100123456789,

注意前面多了個10,表示後面的10位為帳号。如果你接觸過COM裡面的BSTR,應該對這種處理比較熟悉了。接收方收到該字段後,

它知道ISO8583規定第2個字段“帳号”是變長的,是以會先取前面的2位出來,擷取其值,此時為長度,

然後根據該長度值知道應該拷貝該字段後面哪幾位資料,才是真正的帳号。如果你覺得長度如果隻有兩位最多隻能表示99位長,不太夠,

我們也定義可以允許前面3位都為長度的變長字段,這樣就有999位長,應該夠了吧。在規範裡面如果我定義某個字段的屬性是“LLVAR”,

你注意了,其中的LL表示長度,VAR表示後面的資料,兩個LL表示兩位長,最大是99,如果是三位就是“LLLVAR”,最大是999。

這樣看我們定義的ISO8583規範文檔時直接根據這幾個字母就了解某個變長字段的意思了。

該解決的幾個問題到這裡都解決了,我們來回顧下自己設計的ISO8583規範。其實沒有什麼,無非是把金融行業可能出現的資料分門别類,

排好順序,接着把它們連接配接起來,組成一個封包發送出去而已。其中針對該封包的設計進行了一些優化,引入了bit map位圖的概念,

也算是一個不錯的想法。

剩下的工作就簡單了,我們就直接收集金融行業可能出現的資料字段類型,分成128個字段類型,如果沒有到128個這麼多就先保留一些下來,

另外考慮到有些人有特殊的要求,我們規定可以将128個字段中的幾個字段你自己來定義其内容,也算是一種擴充了。

這樣,最後我們就得到了ISO8583規範的那張字段描述表了。想要詳細的知道每個字段的含義直接對着表看就可以,比較簡單。

TPDU

TPDU,全稱Transport Protocol Data Unit,是指傳送協定資料單元。代表從一個傳輸實體發送至另一個傳輸實體的消息。

位圖解析

如将位圖的第一位設為’1’,表示使用擴充位圖(128個域),否則表示隻使用基本位圖(64個域)。

例如:位圖:20 00 38 00 00 00 00 34(64個域)。

你把它解開,

排列一下

20 = 0010 0000

00 = 0000 0000

38 = 0011 1000

依次類推,得到一串數字,總共64位

0010 0000
0000 0000
0011 1000
0000 0000
0000 0000
0000 0000
0000 0000
0011 0100
           

以上資料有多少個1表明需要多少個域的資料,而1的位置表明需要那個域的資料,

以上資料需要3、19、20、21、59、60、62域的資料,以此類推

ISO8583組包格式

封包長度(2位元組)+TPDU(5位元組)+封包頭(6位元組)+域資料(指令碼(0域 2位元組)+位圖(8/16位元組,如果首位元組為1,表示使用擴充域,為16位元組)+其他域資料)

封包長度:從TPDU-封包結尾

一個域資料對象可以包括:

域長度類型:0-9(定長)、0-99(不定長)、0-999(不定長)

域長度:0-999

域編碼類型:BCD、ASCII 、BINARY

其他域資料: 如果 域長度類型是0-9(定長),則其他域資料為:域資料

如果 域長度類型是0-99(不定長),則其他域資料為:計算的1位元組域資料長度+域資料

如果 域長度類型是0-999(不定長), 則其他域資料為:計算的2位元組域資料長度+域資料

參考連結

https://baike.baidu.com/item/8583%E5%8D%8F%E8%AE%AE/5754381?fr=aladdin

http://www.blogjava.net/jjwwhmm/archive/2009/03/31/263041.html

https://wenku.baidu.com/view/d6430445854769eae009581b6bd97f192279bf8b.html

總結

講到這裡我們已經ISO8583的設計初衷,規則,格式,位圖的含義,解包群組包我們隻要按照其格式和規則就可以進行,這裡我想留給讀者自己去思考步驟,當然我會給出Demo給大家,當我們去設計一個程式,我們必須知道這個産品的設計初衷,規則,自己多去思考,先不要着急下手,先在腦子裡有個大緻思路,或者畫個流程圖,我們有時候覺得問題一下子理不清,可以将大問題先化成一個一個小問題,一步一步去解決。這樣對程式才會了解的更加徹底,出了問題也更容易分析,記憶也更加深刻。

Demo GitHub java