`
763691
  • 浏览: 41329 次
  • 性别: 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报文协议包的解析和封装java源代码

    IS08583报文协议包的解析和封装java源代码

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

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

    IS-IS动态路由协议详解

    IS-IS动态路由协议详解: 1.IS-IS协议的基本功能信息 2.路由器的分类 3.ip路由计算过程(建立邻居关系、同步LSDB数据库、执行SPF路由计算) 4.IS-IS路由器级别与区域 5.ISIS报文详解(Hello报文、LSP报文、SNP报文)...

    全面掌握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.

    车载以太网协议IS013400 PDF

    车载以太网协议PDF文档

    IP新技术进阶系列 - 公网IPv4 over SRv6 BE深度解析

    主要内容包含:组网方案、IS-IS全局配置、IS-IS接口配置、IS-IS路由计算、SRv6配置、携带SRv6信息的IS-IS LSP报文格式解析、IS-IS路由计算、在PE上配置End.DT4 SID、PE上生成End.DT4 SID,并加入本地SID表、在PE间...

    wap无线应用协议pdf完整版

    wap无线应用协议pdf完整版,含详细书签,方便查阅 本书目录: 第1章 无线应用协议体系结构规范 第2章 无线应用环境概述 ...第18章 无线控制报文协议规范 第19章 基于GSM无结构化补充业务数据的WAP规范

    wap无线应用协议.RAR

    第1章 无线应用协议体系结构规范.pdf 第2章 无线应用环境概述.pdf 第3章 无线应用环境规范.pdf 第4章 无线标志语言规范.pdf ...第18章 无线控制报文协议规范.pdf 第19章 基于GSM无结构化补充业务数据的WAP规范.pdf

    BICC协议解析

    BICC协议解析(ISUP部分),包含IAM,ACM,ANM,REL,RLC等消息的解析

    配置IS-IS多区域和聚合路由

    掌握基本的is-is路由协议配置 理解L1/L2类型路由 掌握IS-IS区域汇总的配置 实验要求 配置各种路由器的IP地址,并且实验ping命令确认各路由器的直连接口的互通性。 各台路由器的IS-IS配置如下 R1的配置 R1: R1#...

    RS485协议(PDF)

    The principle difference between RS-422 and RS-485 is that the RS-485 driver can be put into a high impedance, tristate mode, which allows other drivers to transmit over the same pair of wires. There ...

    TCPIP协议详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议

    10.9 cp_dpis函数 10.10 cp_reass函数 10.11 小结 第11章 /CP实现:CP输入 11.1 概述 11.2 预处理 11.3 首部预测 11.4 被动打开的启动 11.5 主动打开的启动 11.6 PAWS:防止序号重复 11.7 ACK处理 11.8 完成被动打开...

    IPv6协议学习笔记-地址与报文.pdf

    In the rapid promotion of IPv6 network, increasingly caused people's attention today, people want to ask, IPv6 network is how far? In fact, IPv6 technology is or has been integrated into life

    T122协议英文文档

    The Multipoint Communication Service (MCS) is a generic service designed to support highly interactive multimedia conferencing applications. It supports full-duplex multipoint communication among an ...

    各厂商OSPF经典资料大集合【H3C 华为 思科一网打尽】.rar

    OSPF和IS-IS在NBMA网络中的应用 OSPF学习经验心得 OSPF实验 Ospf的多区域实验2 ospf的注意事项 OSPF知识点 OSPF详细配置 OSPF路由协议中的邻居与邻接 OSPF路由协议验证 OSPF路由聚合的两种方法 OSPF-7种类型LSA ...

    IP新技术进阶系列 - SRv6 Ping&Tracert深度解析

    IS接口配置、IS-IS路由计算、SRv6配置、IS-IS路由计算、查看各个设备的本地SID表、在PE间建立双向SRv6 TE Policy、查看SRv6 TE Policy状态、SRv6 Ping&Tracert介绍、逐段Ping&Tracert检测、逐段Ping检测详细报文格式...

    (视频)IP新技术进阶系列 - SRv6 Ping&Tracert深度解析

    IS接口配置、IS-IS路由计算、SRv6配置、IS-IS路由计算、查看各个设备的本地SID表、在PE间建立双向SRv6 TE Policy、查看SRv6 TE Policy状态、SRv6 Ping&Tracert介绍、逐段Ping&Tracert检测、逐段Ping检测详细报文格式...

    HCIP-RS V2.5 LVC公开课培训视频教程【共128集】.rar

    1.6 IS-IS协议原理与配置 1.7 BGP协议原理与配置 1.8 IP组播基础 1.9 IGMP协议原理与配置 1.10 PIM协议原理与配置 1.11 路由控制 1.12 Eth-Trunk技术原理与配置 1.13 交换机高级特性简介 1.14 RSTP协议原理与配置 ...

    网络互连_网桥.路由器.交换机和互连协议

    第14章讨论各种路由选择协议的特点,包括RIP、IS-IS、OSPF、PNNI、NLSP和BGP。第15章是网络层组播。第16章说明如何设计免受破坏的网络,这在将来会有用。最后两章总结了本书,我希望它们是轻松有趣的。第17章探究了...

    华为HCIP-RS V2.5培训PPT和实验指导手册汇总集.rar

    05 IS-IS协议原理与配置 06 BGP协议原理与配置 07 IP组播基础 08 IGMP协议原理与配置 09 PIM协议原理与配置 10 路由控制 11 Eth-Trunk技术原理与配置 12 交换机高级特性简介 13 RSTP协议原理与配置 14 MSTP...

Global site tag (gtag.js) - Google Analytics