`
763691
  • 浏览: 42520 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

IS08583报文协议

阅读更多

 

I.理论

单纯的讲IS08583那些字段的定义,我觉得没有什么意思,标准中已经对每个字段解释的非常详细了,如果你觉得理解英文版的ISO8583规范有些困难,网上也有同行为我们翻译好的中文版ISO8583规范,所以我的目的是达到阅读本文后能够对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规范的那张字段描述表了。想要详细的知道每个字段的含义直接对着表看就可以,比较简单。

 

II.实践

一:IS08583包介绍:

     ISO8583包(简称8583包)是一个国际标准的包格式,最多由128个字段域组成,每个域都有统一的规定,并有定长与变长之分。
     8583包前面一段为位图,用来确定包的字段域组成情况。其中位图是8583包的灵魂,它是打包解包确定字段域的关键, 而了解每个字段域的属性则是填写数据的基础。   

 1:位图说明:

     位置:在8583包的第1 位
     格式:定长  
     类型:B16(二进制16位,16*8=128bit)  
     描述:  
     如将位图的第一位设为'1',表示使用扩展位图(128个域),否则表示只使用基本位图(64个域)。  
     如使用某数据域,应在位图中将相应的位设位'1',如使用41域,需将位图的41位设为'1'。  
     选用条件:如使用65到128域,需设位图域第一位为'1'  
2:域的定义:  

typedef struct ISO8583  
{  
    int bit_flag;            /*域数据类型0 -- string, 1 -- int, 2 -- binary*/  
    char *data_name;  /*域名*/  
    int length;             /*数据域长度*/  
    int length_in_byte;/*实际长度(如果是变长)*/  
    int variable_flag;   /*是否变长标志0:否 2:2位变长, 3:3位变长*/  
    int datatyp;         /*0 -- string, 1 -- int, 2 -- binary*/  
    char *data;         /*存放具体值*/  
    int attribute;      /*保留*/  
} ISO8583;

 

 

二:定义BitMap类

类说明:根据ISO8583 包的域定义,定义BitMap类存储每个域的信息。例如:

 

package com.lottery.pos.model;

public  class BitMap {
 private int bit; //位
 private int bittype; //数据类型 1 ascii 2 binary
 private int variable;  //是否变长0 不是 2 两位变长 3 三位变长
 private int len; //数据长度
 private byte[] dat; //数据
 
 public int getBit() {
  return bit;
 }
 public void setBit(int bit) {
  this.bit = bit;
 }
 public int getBittype() {
  return bittype;
 }
 public void setBittype(int bittype) {
  this.bittype = bittype;
 }
 public int getVariable() {
  return variable;
 }
 public void setVariable(int variable) {
  this.variable = variable;
 }
 public byte[] getDat() {
  return dat;
 }
 public void setDat(byte[] dat) {
  this.dat = dat;
 }
 public int getLen() {
  return len;
 }
 public void setLen(int len) {
  this.len = len;
 }

 
}

 

 

 

三:定义PortConfig类

类说明:定义配置信息类。根据此类解析和封装数据。例如:

 

package com.lottery.pos.model;

public class PortConfig {
 /**
  * 存放所有接口的配置信息
  * [][0] bit     位:在Map中的位
  * [][1] type   类型:1 ascii 2 binary
  * [][2] len    长度:(对定长有效)
  * [][3] varLen 变长:0非变长 2位变长 3位变长
  */
 // 定义一个二位数组存放配置信息。
 public static final  int[][] config= { 
   {11,1,6,0}, 
   {12,1,6,0},
   {13,1,4,0}, 
   {32,1,11,0},
   {37,1,12,0},
   {39,1,2,0},
   {40,2,50,2},
   {41,1,8,0},
   {48,1,52,3},
   {120,2,128,3},
   };

}

 

 

四:定义BitMapiso类

类说明:此类提供解析请求包和封装信息包两个方法,例如:

 

package com.lottery.pos.utils;

import java.util.ArrayList;
import java.util.List;

import com.lottery.pos.model.BitMap;

public class BitMapiso {

 /**
  * 解析请求包
  * @param body
  * @param config
  * @return List
  */
 @SuppressWarnings("unchecked")
 public static List unpackRequest(byte[] body, int[][] config) {
  List outList = new ArrayList();
  // 取得除信息类型以外的包信息。也就是取得位图的初始位置。
  byte[] realbody = new byte[body.length - 4];
  System.arraycopy(body, 4, realbody, 0, realbody.length);
  // 取得位图
  byte[] map = null;
  byte[] map8 = new byte[8];
  System.arraycopy(realbody, 0, map8, 0, 8);
  boolean[] bmap8 = LoUtils.getBinaryFromByte(map8);
  if (bmap8[1]) {
  // 如果第一位为1,则是可扩展位图,设为16字节长度。
   map = new byte[16];
   System.arraycopy(realbody, 0, map, 0, 16);
  } else {
   map = map8;
  }
  boolean[] bmap = LoUtils.getBinaryFromByte(map);

  int tmplen = map.length;
  for (int i = 2; i < bmap.length; i++) {
   if (bmap[i]) {
    //BitMap bitMap = null;
    // 寻找位图中的1对应的数据
    int bit=-1;
    for (int j = 0; j < config.length; j++) {
     if (config[j][0] == i) {
      bit=j;
      break;
     }
    }
    BitMap outBitMap = new BitMap();
    outBitMap.setBit(i);
    outBitMap.setBittype(config[bit][1]);
    //len对变长是无用的。
    outBitMap.setLen(config[bit][2]);
    outBitMap.setVariable(config[bit][3]);
    byte[] nextData = null;
    if (config[bit][3] > 0) {
     //取出变长部分的值。
     int varLen = config[bit][3];
     if (config[bit][1] == 2) {
      varLen = varLen - 1;
     }
     byte[] varValue = new byte[varLen];
     System.arraycopy(realbody, tmplen, varValue, 0, varValue.length);
     int datLen = 0;
     if (config[bit][1] == 2) {
      datLen = LoUtils.bcdToint(varValue);
     } else {
      datLen = byteToInt(varValue);
     }

     tmplen += varLen;
     // 取出变长部分后带的值。
     nextData = new byte[datLen];

     System.arraycopy(realbody, tmplen, nextData, 0,nextData.length);
     tmplen += nextData.length;
    } else {
     nextData = new byte[config[bit][2]];
     System.arraycopy(realbody, tmplen, nextData, 0,nextData.length);
     tmplen += config[bit][2];
    }
    outBitMap.setDat(nextData);
    outList.add(outBitMap);
   }
  }

  return outList;
 }

 

 /**
  * 打包响应包,不包括消息类型
  * @param list
  * @return byte[]
  */
 @SuppressWarnings("unchecked")
 public static byte[] PackResponse(List list) {
  int len = 16;
  for (int i = 0; i < list.size(); i++) {
   BitMap bitMap = (BitMap) list.get(i);
   // 计算请求包总长度
   if (bitMap.getBittype() == 2) {
    if (bitMap.getVariable() > 0) {
     len += bitMap.getVariable() - 1 + bitMap.getDat().length;
    } else {
     len += bitMap.getVariable() + bitMap.getDat().length;
    }
   } else {
    len += bitMap.getVariable() + bitMap.getDat().length;
   }
  }
  byte[] body = new byte[len];
  // 位图
  boolean[] bbitMap = new boolean[129];
  bbitMap[1] = true;
  int temp = (bbitMap.length - 1) / 8;
  for (int j = 0; j < list.size(); j++) {
   BitMap bitMap = (BitMap) list.get(j);
   bbitMap[bitMap.getBit()] = true;
   byte[] bitmap = LoUtils.getByteFromBinary(bbitMap);
   System.arraycopy(bitmap, 0, body, 0, bitmap.length);
   // 数据
   if (bitMap.getVariable() > 0) {
    // 数据是可变长的:拼变长的值
    byte[] varValue = null;
    if (bitMap.getBittype() == 2) {
     varValue = LoUtils.StrToBCDBytes(String.format("%0"+ bitMap.getVariable() + "d",bitMap.getDat().length));
    } else {
     varValue = String.format("%0" + bitMap.getVariable() + "d",bitMap.getDat().length).getBytes();
    }
    System.arraycopy(varValue, 0, body, temp, varValue.length);
    temp += varValue.length;
    // 拼变长部分后所带的数的值。
    System.arraycopy(bitMap.getDat(), 0, body, temp, bitMap.getDat().length);
    temp += bitMap.getDat().length;
   } else {
    // 数据是固定长度的。
    byte dat[] =new byte[bitMap.getLen()];
    if (bitMap.getDat().length!=bitMap.getLen()){     
     System.arraycopy(bitMap.getDat(), 0, dat, 0, bitMap.getLen());
    }else{
     dat=bitMap.getDat();
    } 
    System.arraycopy(dat, 0, body, temp, dat.length);
    temp += bitMap.getDat().length;
   }
  }
  return body;
 }

 

}

 

 

package com.lottery.utils;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * 编码与数据类型类
 * 
 * @author LLH
 */
public class LoUtils
{
 private static BASE64Encoder encoder = new BASE64Encoder ();
 private static BASE64Decoder decoder = new BASE64Decoder ();
 
 /**
  * BASE64 编码
  * 
  * @param s
  * @return
  */
 public static String encodeBufferBase64(byte [] buff)
 {
  return buff == null ? null : encoder.encode (buff);
 }
 
 /**
  * BASE64解码
  * 
  * @param s
  * @return
  */
 public static byte [] decodeBufferBase64(String s)
 {
  try
  {
   return s == null ? null : decoder.decodeBuffer (s);
  }catch (IOException e)
  {
   e.printStackTrace ();
  }
  return null;
 }
 
 /**
  * BASE64 字节数组编码
  * 
  * @param s
  * @return String
  */
 public static String encodeBase64(byte [] s)
 {
  if(s == null)
   return null;
  String res = new BASE64Encoder ().encode (s);
  res = res.replace ("\n","");
  res = res.replace ("\r","");
  return res;
 }
 
 /**
  * BASE64解码
  * 
  * @param s
  * @return
  */
 public static byte [] decodeBase64(byte [] buff)
 {
  if(buff == null)
   return null;
  BASE64Decoder decoder = new BASE64Decoder ();
  try
  {
   byte [] b = decoder.decodeBuffer (new String (buff));
   
   return b;
  }catch (Exception e)
  {
   return null;
  }
 }
 
 /**
  * 将reauest里的数据包转成字符串
  * 
  * @param request
  * @return String
  */
 public static String getRequestBodyTxt(HttpServletRequest request)
 {
  // 接收手机传过来的参数
  BufferedInputStream bufferedInputStream = null;
  // 此类实现了一个输出流,其中的数据被写入一个字节数组
  ByteArrayOutputStream bytesOutputStream = null;
  String body = null;
  try
  {
   
   // BufferedInputStream 输入流
   bufferedInputStream = new BufferedInputStream (
    request.getInputStream ());
   bytesOutputStream = new ByteArrayOutputStream ();
   // 写入数据
   int ch;
   while ((ch = bufferedInputStream.read ()) != -1)
   {
    bytesOutputStream.write (ch);
   }
   // 转换为String类型
   body = new String (bytesOutputStream.toByteArray (),"UTF-8");
  }catch (Exception ex)
  {
   ex.printStackTrace ();
  }
  finally
  {
   // 关闭此输入流并释放与该流关联的所有系统资源。
   try
   {
    bytesOutputStream.flush ();
    bytesOutputStream.close ();
    bufferedInputStream.close ();
   }catch (IOException e)
   {
    e.printStackTrace ();
   }
  }
  return body;
 }
 
 /**
  * 将reauest里的数据包转成字节数组
  * 
  * @param request
  * @return
  */
 public static byte [] getRequestBodyByte(HttpServletRequest request)
 {
  // 接收手机传过来的参数
  BufferedInputStream bufferedInputStream = null;
  // 此类实现了一个输出流,其中的数据被写入一个字节数组
  ByteArrayOutputStream bytesOutputStream = null;
  byte [] body = null;
  try
  {
   // BufferedInputStream 输入流
   bufferedInputStream = new BufferedInputStream (
    request.getInputStream ());
   bytesOutputStream = new ByteArrayOutputStream ();
   // 写入数据
   int ch;
   while ((ch = bufferedInputStream.read ()) != -1)
   {
    bytesOutputStream.write (ch);
   }
   // 转换为String类型
   body = bytesOutputStream.toByteArray ();
  }catch (Exception ex)
  {
   ex.printStackTrace ();
  }
  finally
  {
   // 关闭此输入流并释放与该流关联的所有系统资源。
   try
   {
    bytesOutputStream.flush ();
    bytesOutputStream.close ();
    bufferedInputStream.close ();
   }catch (IOException e)
   {
    e.printStackTrace ();
   }
  }
  return body;
 }
 
 public static String getEigthBitsStringFromByte(int b)
 {
  // if this is a positive number its bits number will be less
  // than 8
  // so we have to fill it to be a 8 digit binary string
  // b=b+100000000(2^8=256) then only get the lower 8 digit
  b |= 256; // mark the 9th digit as 1 to make sure the string
  // has at
  // least 8 digits
  String str = Integer.toBinaryString (b);
  int len = str.length ();
  return str.substring (len - 8,len);
 }
 
 public static byte getByteFromEigthBitsString(String str)
 {
  // if(str.length()!=8)
  // throw new Exception("It's not a 8 length string");
  byte b;
  // check if it's a minus number
  if(str.substring (0,1).equals ("1"))
  {
   // get lower 7 digits original code
   str = "0" + str.substring (1);
   b = Byte.valueOf (str,2);
   // then recover the 8th digit as 1 equal to plus
   // 1000000
   b |= 128;
  }
  else
  {
   b = Byte.valueOf (str,2);
  }
  return b;
 }
 
 /**
  * 将一个16字节数组转成128二进制数组
  * 
  * @param b
  * @return
  */
 public static boolean [] getBinaryFromByte(byte [] b)
 {
  boolean [] binary = new boolean [b.length * 8 + 1];
  String strsum = "";
  for (int i = 0;i < b.length;i++ )
  {
   strsum += getEigthBitsStringFromByte (b [i]);
  }
  for (int i = 0;i < strsum.length ();i++ )
  {
   if(strsum.substring (i,i + 1).equalsIgnoreCase ("1"))
   {
    binary [i + 1] = true;
   }
   else
   {
    binary [i + 1] = false;
   }
  }
  return binary;
 }
 
 /**
  * 将一个128二进制数组转成16字节数组
  * 
  * @param binary
  * @return
  */
 public static byte [] getByteFromBinary(boolean [] binary)
 {
  
  int num = (binary.length - 1) / 8;
  if((binary.length - 1) % 8 != 0)
  {
   num = num + 1;
  }
  byte [] b = new byte [num];
  String s = "";
  for (int i = 1;i < binary.length;i++ )
  {
   if(binary [i])
   {
    s += "1";
   }
   else
   {
    s += "0";
   }
  }
  String tmpstr;
  int j = 0;
  for (int i = 0;i < s.length ();i = i + 8)
  {
   tmpstr = s.substring (i,i + 8);
   b [j] = getByteFromEigthBitsString (tmpstr);
   j = j + 1;
  }
  return b;
 }
 
 /**
  * 将一个byte位图转成字符串
  * 
  * @param b
  * @return
  */
 public static String getStrFromBitMap(byte [] b)
 {
  String strsum = "";
  for (int i = 0;i < b.length;i++ )
  {
   strsum += getEigthBitsStringFromByte (b [i]);
  }
  return strsum;
 }
 
 /**
  * bytes转换成十六进制字符串
  * 
  * @param b
  * @return
  */
 public static String byte2HexStr(byte [] b)
 {
  String hs = "";
  String stmp = "";
  for (int n = 0;n < b.length;n++ )
  {
   stmp = (Integer.toHexString (b [n] & 0XFF));
   if(stmp.length () == 1)
    hs = hs + "0" + stmp;
   else
    hs = hs + stmp;
  }
  return hs.toUpperCase ();
 }
 
 private static byte uniteBytes(String src0, String src1)
 {
  byte b0 = Byte.decode ("0x" + src0).byteValue ();
  b0 = (byte) (b0 << 4);
  byte b1 = Byte.decode ("0x" + src1).byteValue ();
  byte ret = (byte) (b0 | b1);
  return ret;
 }
 
 /**
  * 十六进制字符串转换成bytes
  * 
  * @param src
  * @return
  */
 public static byte [] hexStr2Bytes(String src)
 {
  int m = 0, n = 0;
  int l = src.length () / 2;
  byte [] ret = new byte [l];
  for (int i = 0;i < l;i++ )
  {
   m = i * 2 + 1;
   n = m + 1;
   ret [i] = uniteBytes (src.substring (i * 2,m),
    src.substring (m,n));
  }
  return ret;
 }
 
 /**
  * 将String转成BCD码
  * 
  * @param s
  * @return
  */
 public static byte [] StrToBCDBytes(String s)
 {
  
  if(s.length () % 2 != 0)
  {
   s = "0" + s;
  }
  ByteArrayOutputStream baos = new ByteArrayOutputStream ();
  char [] cs = s.toCharArray ();
  for (int i = 0;i < cs.length;i += 2)
  {
   int high = cs [i] - 48;
   int low = cs [i + 1] - 48;
   baos.write (high << 4 | low);
  }
  return baos.toByteArray ();
 }
 
 /**
  * 将BCD码转成int
  * 
  * @param b
  * @return
  */
 public static int bcdToint(byte [] b)
 {
  StringBuffer sb = new StringBuffer ();
  for (int i = 0;i < b.length;i++ )
  {
   int h = ((b [i] & 0xff) >> 4) + 48;
   sb.append ((char) h);
   int l = (b [i] & 0x0f) + 48;
   sb.append ((char) l);
  }
  return Integer.parseInt (sb.toString ());
 }
 
 /**
  * 输出调试信息
  * 
  * @param str
  */
 public static void trace(String str)
 {
//  System.out.println ("["
//   + (new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.S")).format (new Date ())
//   + "]>" + str);
 }
}


 

 

原文转载于http://www.cnblogs.com/dengzhaozhe/archive/2009/05/09/1453251.html 

                 http://hi.baidu.com/mytaihu/blog/item/96e11d24d07f8320d507420d.html

分享到:
评论

相关推荐

    is08583银联通讯协议

    IS08583协议详解 IS08583是一种广泛应用在金融行业,特别是银行卡交易中的通信协议。它主要用于银行间或者银行与商户、ATM等终端之间的数据交换,处理包括但不限于授权、清算、查询、撤销等交易类型。这个协议定义...

    IS-IS协议的报文类型和路由泄漏.doc

    "IS-IS 协议的报文类型和路由泄漏" _IS-IS 协议是一种基于 OSI 参考模型的链路状态路由协议,主要用于大型企业网络和 ISP 网络中。_ _IS-IS 协议的报文类型_ IS-IS 协议的报文类型共有 9 种,分别是: 1. Hello ...

    IS-IS协议详解.doc

    IS-IS协议,全称Intermediate System to Intermediate System,是一种链路状态路由协议,常用于大型网络的路由决策。它与OSPF有许多相似之处,但也有其独特的特点和优势。以下是对IS-IS协议的详细阐述。 首先,IS-...

    IS-IS协议学习01

    IS-IS协议,全称为Intermediate System to Intermediate System,是网络层的一种路由协议,主要应用于OSI模型的第二层和第三层,常被用在网络中的路由选择。IS-IS协议的设计初衷是为了在大型分组交换网络中提供高效...

    IS-IS路由协议中文教程

    IS-IS通过Hello报文建立邻居关系,通过LSP(Link State Packet)交换链路状态信息,这些信息被汇总成链路状态数据库(LSDB)。LSDB用于运行SPF(Shortest Path First)算法,生成最短路径树,最终形成路由表。 ####...

    IS-IS动态路由协议详解

    6. **TLV数据结构**:在IS-IS报文中,使用Type-Length-Value(TLV)编码结构携带各种信息,增强了协议的扩展性和灵活性。 7. **工作过程**:IS-IS协议的工作流程包括网络初始化、邻接关系建立、路由信息传播、路由...

    学习IS-IS路由协议

    - **Hello报文**:IS-IS通过发送Hello报文来发现邻居,并建立邻接关系。 - **链路状态广告(LSA)**:一旦建立了邻接关系,IS-IS节点会通过LSA来传播网络拓扑信息。这些信息会被其他节点用于构建网络拓扑数据库。 ...

    IS-IS协议基础篇

    - IS-IS协议通过发送Hello报文来建立和维护邻接关系。路由器发送IS Hello报文(ISH),而终端系统发送ES Hello报文(ESH)。 ##### 2. **链路状态数据库(LSDB)** - 每个IS-IS路由器都会维护一个链路状态数据库...

    IS-IS协议基本配置实验(初学版)

    6. **设置Hello报文参数**:IS-IS协议通过Hello报文进行邻居发现和状态同步。可以配置Hello间隔、Hold时间等参数,以适应不同网络环境的需求。 7. **配置路由汇总**:为了减少路由表的大小和提高效率,可以使用路由...

    车载以太网协议IS013400 PDF

    车载以太网协议ISO13400是汽车行业在向智能网联汽车发展的过程中,为满足高带宽、低延迟通信需求而制定的一种标准。它旨在提升车辆内部数据传输的效率,确保网络的稳定性和安全性,同时降低布线成本。这篇PDF文档...

    30分钟你能了解多少IS-IS协议.doc

    两者在很多方面有相似之处,如都维护一个链接状态数据库(LSDB),并使用最短路径优先(SPF)算法计算最佳路径,通过Hello报文建立和维护邻居关系,具有构建层次化网络的区域概念,都是无类路由协议,以及在广播型多...

    HM-047 IS-IS路由协议(V5.1)

    IS-IS路由协议是一种基于链路状态的网络路由协议,它最初设计用于OSI网络模型,但现在广泛应用于TCP/IP网络中,成为了现代IP网络的核心路由协议之一。IS-IS的优势在于其高效、快速的路由收敛能力,支持大规模网络...

    专题(2021-2022年)精品课件华为IS-IS路由协议培训胶片.ppt

    IS-IS路由协议,全称Intermediate System to Intermediate System,是一种用于分组交换网络的链路状态路由协议,由国际标准化组织ISO开发,最初设计用于CLNP(Connectionless Network Protocol)网络。随着时间的...

    YD-T_1251.1-2003_路由协议一致性测试方法—_中间系统到中间系统路由交换协议(is-is)

    2. **Hello协议**:IS-IS使用Hello报文进行邻接发现和链路维护,路由器通过周期性发送Hello报文来确定相邻节点并建立邻接关系。 3. **SPF算法**:IS-IS使用最短路径优先(Shortest Path First, SPF)算法计算网络...

    IS31FL3236A 驱动程序,IIC通信

    IS31FL3236A是一款高集成度的LED...总的来说,IS31FL3236A与STM32的I²C通信涉及了嵌入式系统中的硬件接口设计、串行通信协议、微控制器编程等多个知识点,通过掌握这些,我们可以构建出灵活、高效的RGB灯光控制系统。

    全面掌握ISO8583报文协议.rar_ISO8583_The Request

    If the property value is not null, the field value is still compiled from that property value. If the field is TLV field (see section Element tlv) then it will call CompileTlv to get the field value.

    路由协议操作手册(IP RIP OSPF IS-IS LSP BGP MBGP)

    - **配置IS-IS报文中路由权值的类型**:设置路由权值类型。 以上是该操作手册中的主要知识点总结。这些知识点覆盖了IP路由协议的基础理论和实际配置方法,对于网络工程师理解和部署路由协议具有重要的参考价值。

Global site tag (gtag.js) - Google Analytics