﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-anselly</title><link>http://www.blogjava.net/anselly/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 07 May 2026 01:59:42 GMT</lastBuildDate><pubDate>Thu, 07 May 2026 01:59:42 GMT</pubDate><ttl>60</ttl><item><title>8583</title><link>http://www.blogjava.net/anselly/archive/2011/06/02/351624.html</link><dc:creator>anselly</dc:creator><author>anselly</author><pubDate>Thu, 02 Jun 2011 10:39:00 GMT</pubDate><guid>http://www.blogjava.net/anselly/archive/2011/06/02/351624.html</guid><wfw:comment>http://www.blogjava.net/anselly/comments/351624.html</wfw:comment><comments>http://www.blogjava.net/anselly/archive/2011/06/02/351624.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/anselly/comments/commentRss/351624.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anselly/services/trackbacks/351624.html</trackback:ping><description><![CDATA[<span style="font-family: Courier; font-size: 12pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">最开始时，金融系统只有<span lang="EN-US">IBM</span>这些大的公司来提供设备，象各种主机与终端等。在各个计算机设备之间，需要交换数据。我们知道数据是通过网络来传送的，而在网络上传送的数据都是基于<span lang="EN-US">0</span>或<span lang="EN-US">1</span>这样的二进制数据，如果没有对数据进行编码，则这些数据没有人能够理解，属于没有用的数据。起初的<span lang="EN-US">X.25</span>、<span lang="EN-US">SDLC</span>以及现在流行的<span lang="EN-US">TCP/IP</span>网络协议都提供底层的通讯编码协议，它们解决了最底层的通讯问题，能够将一串字符从一个地方传送到另一个地方。但是，仅仅传送字符串是没有太大意义的，怎样来解析字符串代表什么内容是非常重要的，否则传送一些&#8220;<span lang="EN-US">0123abcd</span>&#8221;的字符串也是无用的乱码。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>让我们随着时光回到几十年前的某个时刻，假设我们被推到历史的舞台上，由我们来设计一个通用报文协议，来解决金融系统之间的报文交换，暂且称该协议叫做<span lang="EN-US">ISO8583</span>协议。此时，技术是在不断的前行，当初<span lang="EN-US">IBM</span>一支独秀的局面好像已经不妙了，各种大小不一的公司都进入金融行业以求能有所斩获，呈一片百花齐放的局面。我们怎样来设计一个报文协议，能够将这些如雨后春笋般出现的所有公司都纳入进来，其实也不是一件很简单的事。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>我们还是先一步步的来考虑吧。金融行业其实涉及到的数据内容并不是成千上万，无法统计，恰恰相反，是比较少的。我们都可以在心底数得过来，象交易类型、帐号、帐户类型、密码、交易金额、交易手续费、日期时间、商户代码、<span lang="EN-US">2</span>磁<span lang="EN-US">3</span>磁数据、交易序列号等，把所有能够总结出来的都总结起来不过<span lang="EN-US">100</span>个左右的数据。那我们可以首先简单的设计<span lang="EN-US">ISO8583</span>，定义<span lang="EN-US">128</span>个字段，将所有能够考虑到的类似上面提到的&#8220;帐号&#8221;等金融数据类型，按照一个顺序排起来，分别对应<span lang="EN-US">128</span>个字段中的一个字段。每个数据类型占固定的长度，这个顺序和长度我们都事先定义好。这样就简单了，要发送一个报文时，就将<span lang="EN-US">128</span>个字段按照顺序接起来，然后将接起来的整串数据包发送出去。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>任何金融软件收到<span lang="EN-US">ISO8583</span>包后，直接按照我们定义的规范解包即可，因为整个报文的<span lang="EN-US">128</span>个字段从哪一位到哪一位代表什么，大家都知道，只要知道你的数据包是<span lang="EN-US">ISO8583</span>包即可，我们都已经定义好了。比如第<span lang="EN-US">1</span>个字段是&#8220;交易类型&#8221;，长度为<span lang="EN-US">4</span>位，第<span lang="EN-US">2</span>个字段位是&#8220;帐号&#8221;，为<span lang="EN-US">19</span>位等等。接收方就可以先取<span lang="EN-US">4</span>位，再取接着的<span lang="EN-US">19</span>位，依次类推，直到整个数据包<span lang="EN-US">128</span>个字段都解完为止。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>其实这种做法真是简单直接，基本上就可以满足需要了。不过我们有几个问题要思考下：<span lang="EN-US"><br />1</span>、 我怎么知道每个字段的数据类型呢，是数字还是字符？<span lang="EN-US"><br />2</span>、 每个传送的报文都把<span lang="EN-US">128</span>个字段都传过去，那网络带宽能够承受得了，有时候我可能只需要其中<span lang="EN-US">5</span>个字段，结果多收到了<span lang="EN-US">123</span>个无用的字段。<span lang="EN-US"><br />3</span>、 如果我某些字段的长度不固定，属于变长怎么办，因为你现在解包是当作数据包每个字段都是固定的，用<span lang="EN-US">C</span>语言解包时直接依靠指针取固定长度的一串字符做为一个字段。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>我们来一一解决这些问题。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>第一个问题简单，我在定义<span lang="EN-US">ISO8583</span>时除了定义每个字段表示什么，还规定其内容是数字或是字符等即可。考虑可能出现的类型不过有以下几种：字母、数字、特殊字符、年月日等时间、二进制数据。比如我对<span lang="EN-US">128</span>个字段中的&#8220;商户类型&#8221;字段定义其长度是<span lang="EN-US">15</span>，同时定义其类型为字母。再精细点，如果&#8220;商户类型&#8221;里面的数据同时包括数字和字母呢？那我们就定义其类型为字母也可，为数字也可，即一个字段可以同时属于多个类型。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>第二个问题稍微复杂点。其本质就是如果我只传<span lang="EN-US">128</span>个字段的<span lang="EN-US">5</span>个字段，接收方怎么知道我传了哪几个字段给它了。要是我们把剩下的<span lang="EN-US">123</span>全部填成<span lang="EN-US">0</span>或其他特殊标识，标明该字段不需要使用？这种处理方法没有半点用处，没有解决网络带宽的本质问题，还是要传<span lang="EN-US">128</span>个字段。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>换个思路，我在报文前面加上个包头，包头里面包含的信息能够让别人知道只传了<span lang="EN-US">5</span>个字段。怎样设计这个包头，可以这样，我们用<span lang="EN-US">16</span>个字节，即<span lang="EN-US">128</span>个<span lang="EN-US">bit</span>（一个字节等于<span lang="EN-US">8bit</span>）来表示<span lang="EN-US">128</span>个字段中的某个字段是否存在。每个<span lang="EN-US">bit</span>在计算机的二进制里面不是<span lang="EN-US">1</span>就是<span lang="EN-US">0</span>，如果是<span lang="EN-US">1</span>就表示对应的字段在本次报文中存在，如果是<span lang="EN-US">0</span>就是不存在。这样好了，如果别人接收到了<span lang="EN-US">ISO8583</span>报文，可以先根据最前面的报文头，就知道紧接着报文头后面的报文有哪些字段，没有哪些字段了。比如，我要发送<span lang="EN-US">5</span>个字段，分别属于<span lang="EN-US">128</span>个字段中的第<span lang="EN-US">2</span>、<span lang="EN-US">3</span>、<span lang="EN-US">6</span>、<span lang="EN-US">8</span>、<span lang="EN-US">9</span>字段，我就可以将<span lang="EN-US">128bit</span>的报文头填成<span lang="EN-US">011001011000000000</span>&#8230;&#8230;&#8230;<span lang="EN-US">..</span>，一共<span lang="EN-US">128</span>个<span lang="EN-US">bit</span>，后面就全是<span lang="EN-US">0</span>了。注意其中第<span lang="EN-US">2</span>、<span lang="EN-US">3</span>、<span lang="EN-US">6</span>、<span lang="EN-US">8</span>、<span lang="EN-US">9</span>位为<span lang="EN-US">1</span>，其他都为<span lang="EN-US">0</span>。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>有了这个<span lang="EN-US">128bit</span>的报文头，我们就可以只发送需要的<span lang="EN-US">5</span>个字段了。怎样组织报文？先放上这<span lang="EN-US">128bit</span>，即<span lang="EN-US">16</span>个字节的头，然后在头后面放<span lang="EN-US">2</span>、<span lang="EN-US">3</span>、<span lang="EN-US">6</span>、<span lang="EN-US">8</span>、<span lang="EN-US">9</span>字段，这些字段紧挨在一起，<span lang="EN-US">3</span>和<span lang="EN-US">6</span>之间也不需要填上<span lang="EN-US">4</span>、<span lang="EN-US">5</span>这两个字段了。接收方收到这个报文，它会根据<span lang="EN-US">128bit</span>的报文头来解包，它自然知道把第<span lang="EN-US">3</span>个字段取出后，就直接在第<span lang="EN-US">3</span>字段的后面取第<span lang="EN-US">6</span>个字段，每个字段的长度在<span lang="EN-US">ISO8583</span>里面都定义好了，很轻松就把数据包解出来了。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>这下好了，为了解决上面的第二问题，我们只是在报文中增加了<span lang="EN-US">16</span>个字节的数据，就轻松搞定了，我们把这<span lang="EN-US">16</span>个字节称为<span lang="EN-US">bit map</span>，即位图，用来表示某个位是否存在。不过我们再稍微优化一下，考虑到很多时候报文不需要<span lang="EN-US">128</span>个字段这么多，其一半<span lang="EN-US">64</span>个字段都不一定能够用完。那我可以将报文头由<span lang="EN-US">128bit</span>减到<span lang="EN-US">64bit</span>，只有在需要的时候才把剩下的<span lang="EN-US">64bit</span>放到报文里面，这样报文长度不又少了<span lang="EN-US">8</span>个字节吗？<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>是个好主意。我们把<span lang="EN-US">ISO8583</span>的<span lang="EN-US">128</span>个字段中最常见的都放到前<span lang="EN-US">64</span>个字段中，那我们可以将处理缩小一倍。这样我一般发送报文时只需发送<span lang="EN-US">64bit</span>，即一个字节的报文头，再加上需要的几个字段就可以了。如果有些报文用到<span lang="EN-US">64</span>到<span lang="EN-US">128</span>之间的字段呢？这个也好办，我把<span lang="EN-US">64bit</span>报文头的第一位<span lang="EN-US">bit</span>用来代表特殊含义，如果该<span lang="EN-US">bit</span>为<span lang="EN-US">1</span>，则表示<span lang="EN-US">64bit</span>后面跟了剩下的<span lang="EN-US">64bit</span>报文头；如果第一位<span lang="EN-US">bit</span>为<span lang="EN-US">0</span>，则表示<span lang="EN-US">64bit</span>后面没有跟剩下的<span lang="EN-US">64bit</span>报文头，直接是<span lang="EN-US">128</span>个字段中的报文了。那们，接收方会判断一下报头的第一个<span lang="EN-US">bit</span>是<span lang="EN-US">1</span>还是<span lang="EN-US">0</span>，从而知道报文头是<span lang="EN-US">64bit</span>还是<span lang="EN-US">128bit</span>了，就可以做相应处理。因为报文头第二个<span lang="EN-US">64bit</span>属于有时候有，所以我们叫它<span lang="EN-US">Extended bit map</span>扩展位图，相应的报文头最开始的<span lang="EN-US">64bit</span>我们叫它<span lang="EN-US">Primary bit map</span>主位图。我们直接把扩展位图固定放到<span lang="EN-US">128</span>个字段的第一个字段，而主位图每个数据包都有，就强制性放在所有<span lang="EN-US">128</span>个字段的前面，并不归入<span lang="EN-US">128</span>个字段中去。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>第三个问题可以考虑这样解决。比如第<span lang="EN-US">2</span>个字段是&#8220;帐号&#8221;，是不定长的，可能有的银行帐号是<span lang="EN-US">19</span>位，有的是<span lang="EN-US">17</span>位等。我们定<span lang="EN-US">ISO8583</span>规范时可以规定第<span lang="EN-US">2</span>个字段是<span lang="EN-US">25</span>位，这下足够将<span lang="EN-US">19</span>和<span lang="EN-US">17</span>的情况都包含进来，但是如果以后出现了<span lang="EN-US">30</span>位的怎么办？那我们现在将字段定为<span lang="EN-US">100</span>位。以后超过<span lang="EN-US">100</span>位怎么办，况且如果你只有<span lang="EN-US">19</span>位的帐号，我们定义了<span lang="EN-US">100</span>位，那<span lang="EN-US">81</span>位的数据不是浪费了网络的带宽。看来预先定义一个我们认为比较大的位数是不太好的。<span lang="EN-US"><br />&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span>我们这样，对于第<span lang="EN-US">2</span>个字段&#8220;帐号&#8221;，在字段的开头加上&#8220;帐号&#8221;的长度。比如帐号是<span lang="EN-US">0123456789</span>，一共<span lang="EN-US">10</span>位，我们变成<span lang="EN-US">100123456789</span>，注意前面多了个<span lang="EN-US">10</span>，表示后面的<span lang="EN-US">10</span>位为帐号。如果你接触过<span lang="EN-US">COM</span>里面的<span lang="EN-US">BSTR</span>，应该对这种处理比较熟悉了。接收方收到该字段后，它知道<span lang="EN-US">ISO8583</span>规定第<span lang="EN-US">2</span>个字段&#8220;帐号&#8221;是变长的，所以会先取前面的<span lang="EN-US">2</span>位出来，获取其值，此时为长度，然后根据该长度值知道应该拷贝该字段后面哪几位数据，才是真正的帐号。如果你觉得长度如果只有两位最多只能表示<span lang="EN-US">99</span>位长，不太够，我们也定义可以允许前面<span lang="EN-US">3</span>位都为长度的变长字段，这样就有<span lang="EN-US">999</span>位长，应该够了吧。在规范里面如果我定义某个字段的属性是&#8220;<span lang="EN-US">LLVAR</span>&#8221;，你注意了，其中的<span lang="EN-US">LL</span>表示长度，<span lang="EN-US">VAR</span>表示后面的数据，两个<span lang="EN-US">LL</span>表示两位长，最大是<span lang="EN-US">99</span>，如果是三位就是&#8220;<span lang="EN-US">LLLVAR</span>&#8221;，最大是<span lang="EN-US">999</span>。这样看我们定义的<span lang="EN-US">ISO8583</span>规范文档时直接根据这几个字母就理解某个变长字段的意思了。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>该解决的几个问题到这里都解决了，我们来回顾下自己设计的<span lang="EN-US">ISO8583</span>规范。其实没有什么，无非是把金融行业可能出现的数据分门别类，排好顺序，接着把它们连接起来，组成一个报文发送出去而已。其中针对该报文的设计进行了一些优化，引入了<span lang="EN-US">bit map</span>位图的概念，也算是一个不错的想法。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>剩下的工作就简单了，我们就直接收集金融行业可能出现的数据字段类型，分成<span lang="EN-US">128</span>个字段类型，如果没有到<span lang="EN-US">128</span>个这么多就先保留一些下来，另外考虑到有些人有特殊的要求，我们规定可以将<span lang="EN-US">128</span>个字段中的几个字段你自己来定义其内容，也算是一种扩展了。<span lang="EN-US"><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span>这样，最后我们就得到了<span lang="EN-US">ISO8583</span>规范的那张字段描述表了。想要详细的知道每个字段的含义直接对着表看就可以，比较简单。</span> <img src ="http://www.blogjava.net/anselly/aggbug/351624.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anselly/" target="_blank">anselly</a> 2011-06-02 18:39 <a href="http://www.blogjava.net/anselly/archive/2011/06/02/351624.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>