等待高手:如何用JAVA制作一个8583报文的监听器?

oicqren 2004-09-21 05:46:52
想制作一个8583报文的监听器,请高手说一下制作原理,用到那些类。
如果能有源码来看当然更好。
...全文
875 点赞 收藏 22
写回复
22 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
oicqren 2004-09-28
请问能不能在msn上交流?(MSN:james_zj@msn.com)
回复
oicqren 2004-09-28
看了代码受益匪浅,有几个问题:
validate(); 方法在做什么?我需要验证吗?
abstract class Field类怎么实现?下面应该是Field类的几个抽象数据:
/* 域数据类型0 -- string, 1 -- int, 2 -- binary */
/* 域名 */
/* 数据域长度 */
/* 实际长度(如果是变长) */
/* 是否变长标志0:否 2:2位变长,3:3位变长 */
/* 0 -- string, 1 -- int, 2 -- binary */
/* 存放具体值 */
/* 保留 */
肯定是具体的存放值有些区别,有的是String, 有的是金额,有的是binary。对吧!难道你有3个field类?
还有你的这段代码没通过factory创建域信息呀?只是在取而已!
//这里得到位元信息,通过factory创建域信息,并加到fields中
for(int i=0,k=fields.size();i<k;i++){
Field f=(Field)fields.get(i);
f.read(is);
}
field也有read(InputStream is)方法?在做什么用?
你的Message的构造函数是什么?
我从Socket readline()得到的是String怎么能用你这个Message()呢?
回复
flyxxxxx 2004-09-28
这样做的好处是,每增加修改一种新的报文只要实现一个Message的子类,以及修改一个MessageFactory的newMessage方法,避免了大量重复工作
回复
flyxxxxx 2004-09-28
对所有域先进行一个分类,对同一类的实现一个Field,由FieldFactory来根据索引构造。
对所有类型的报文实现Message,此报文是知道哪些Field是必须的和可选的,因此由Message类来读写,由子类进行数据校验。
回复
flyxxxxx 2004-09-28
你这样做只是把报文拆分成多个域,对于每种报文还得把每个域变成需要的数据和把数据变成域,每种报文写一次,测试会累死你。
class MessageFactory{
public Message newMessage(String type);//从流中读取报文头,得到报文类型,根据类型生成Message的子类。
}
class FieldFactory{
public Field getField(int index);//根据索引生成一个域,因为所有类型的报文的同一个域是完全一样的。
}
abstract class Message{
ArrayList fields=new ArrayList();//所有的域
public void read(InputStream is){
FieldFactory factory=new FieldFactory();
//这里得到位元信息,通过factory创建域信息,并加到fields中
for(int i=0,k=fields.size();i<k;i++){
Field f=(Field)fields.get(i);
f.read(is);
}
//到这里已读完数据,下一步是调用一个要子类实现的抽象方法,对数据进行校验。
validate();
}
public Field getField(int index);
abstrace protected boolean validate();
}
回复
oicqren 2004-09-28
我实在是不愿意贴出代码来给大家看,先道歉。
回复
oicqren 2004-09-28

/*
* Created on 2004-9-23
* TODO 将8583报文转换成数组的类
*/
package iso;

import java.util.BitSet;

/**
* @author james
*/
public class ISO8583Mes
{
private String originalMes; // 原始报文

private ISO8583Field[] result = ISO8583Util.createDefaultFieldStructure(); // 最终由8583报文转换成的数据数组

private BitSet bitmap_base = new BitSet(); // 基本位图

private BitSet bitmap_extend; // 扩展位图

private boolean extendFlag = false;

/**
* @param originalStr
*/
public ISO8583Mes(String originalMes)
{
this.originalMes = originalMes;
byte[] tmpByteArray = this.originalMes.getBytes(); // 由originalMes转换成的一个byte数组
// 先取出一个byte
byte tmpByte = tmpByteArray[0]; // 报文的第一个byte
// 判断是否有扩展位图
if ( ISO8583Util.getPositionValue(tmpByte, 1) )
{
bitmap_extend = new BitSet();
extendFlag = true;
}
// 初始化基本位图
int tmpByteArray_counter = 0; // tmpByeArray数组当前已使用了几个byte
while (tmpByteArray_counter < 8)
{
tmpByte = tmpByteArray[tmpByteArray_counter];
tmpByteArray_counter++;
for ( int i = 0; i < 8; i++ )
{
bitmap_base.set((tmpByteArray_counter - 1) * 8 + i, ISO8583Util
.getPositionValue(tmpByte, i));
}
}
// 初始化扩展位图
if ( extendFlag )
{
while (tmpByteArray_counter < 16)
{
tmpByte = tmpByteArray[tmpByteArray_counter];
tmpByteArray_counter++;
for ( int i = 0; i < 8; i++ )
{
bitmap_extend.set((tmpByteArray_counter - 1) * 8 + i,
ISO8583Util.getPositionValue(tmpByte, i));
}
}
}
// 基本位图已经处理完毕,下面要开始取数据
// i从1开始循环是因为map[0]代表扩展的64位是否有效,代表数据的位图要从map[1]开始
byte[] fieldByteArray; // 域的临时串
byte[] fieldByteLenArray; // 变长域的临时长度
for ( int i = 1; i < bitmap_base.size(); i++ )
{
if ( bitmap_base.get(i) )
{
// i位有效,则根据8583的标准查找第i个位元代表什么意义,应该往后截几个byte
ISO8583Field fld = result[i];

if (fld.getVariableFlag() == 0) // 定长
{
// 取数据
fieldByteArray = new byte[fld.getLength()];
for (int fi=0;i<fld.getLength();i++)
{
fieldByteArray[i] = tmpByteArray[tmpByteArray_counter];
tmpByteArray_counter++;
}
}
else // 变长 2、3两种情况
{
// 取长度
fieldByteLenArray = new byte[fld.getVariableFlag()];
for (int fi=0;i<fld.getVariableFlag();i++)
{
fieldByteLenArray[i] = tmpByteArray[tmpByteArray_counter];
tmpByteArray_counter++;
}
fld.setLengthTrue(Integer.parseInt(new String(fieldByteLenArray)));
// 取数据
fieldByteArray = new byte[fld.getLengthTrue()];
for (int fi=0;i<fld.getLengthTrue();i++)
{
fieldByteArray[i] = tmpByteArray[tmpByteArray_counter];
tmpByteArray_counter++;
}
}
result[i].setData(new String(fieldByteArray));
}
}
if ( extendFlag )
{
for ( int i = 0; i < bitmap_extend.size(); i++ )
{
if ( bitmap_extend.get(i) )
{
// i位有效,则根据8583的标准查找第i个位元代表什么意义,应该往后截几个byte
ISO8583Field fld = result[i];

if (fld.getVariableFlag() == 0) // 定长
{
// 取数据
fieldByteArray = new byte[fld.getLength()];
for (int fi=0;i<fld.getLength();i++)
{
fieldByteArray[i] = tmpByteArray[tmpByteArray_counter];
tmpByteArray_counter++;
}
}
else // 变长 2、3两种情况
{
// 取长度
fieldByteLenArray = new byte[fld.getVariableFlag()];
for (int fi=0;i<fld.getVariableFlag();i++)
{
fieldByteLenArray[i] = tmpByteArray[tmpByteArray_counter];
tmpByteArray_counter++;
}
fld.setLengthTrue(Integer.parseInt(new String(fieldByteLenArray)));
// 取数据
fieldByteArray = new byte[fld.getLengthTrue()];
for (int fi=0;i<fld.getLengthTrue();i++)
{
fieldByteArray[i] = tmpByteArray[tmpByteArray_counter];
tmpByteArray_counter++;
}
}
result[64+i].setData(new String(fieldByteArray));
}
}
}

}
public BitSet getBitmap_base()
{
return bitmap_base;
}
public BitSet getBitmap_extend()
{
return bitmap_extend;
}
public boolean isExtendFlag()
{
return extendFlag;
}
public String getOriginalMes()
{
return originalMes;
}
public ISO8583Field[] getResult()
{
return result;
}
}
回复
oicqren 2004-09-28
to flyxxxxx(灭神) :感谢你的大力支持,看来你是一个非常厉害的架构设计师。现在不能结贴,否则已经把100分加给你了。能不能再跟我说说8583报文解析和组装的动作实现,我已经作了一些类,但是不知道解析报文部分对不对。对于我来说特别好的结构并不重要,考虑扩展性也是未雨绸缪,我要做的事情就是把通讯某块、拆报文模块实现好,而其中的重点是拆报文,这部分我已经做出来了,可是之前没有用java做这个的经验,而且我在网上搜索了好几天,找到的都是c做的,所以不知道能否使用,我周围没有给我发报文的调试环境,所以也无法测试我的解析模块,这样我又要自己来做个发报文的模块,我又不能保证发报文模块作的是正确的,所以faint... 只好发贴子上来问
现在详细说一下我的问题:
ISO8583Rev.class // 只用作接收报文用
ISO8583Mes.class // 接收到报文后,发给这个类,由它拆报文,生成报文数组
ISO8583Field.class // 报文数组中每一个域的类
ISO8583Bean.class // 报文我是有了,但只有一部分数据是我需要的,所以放到这里边发给其他的模块使用
ISO8583Util.class // Mes.class的帮助类
ISO8583Sed.class // 模拟ATM等终端发送8583报文的类

问题:
我在ISO8583Mes中实现了拆报文的逻辑,可不知道能否使用,想听听高手的意见。
下面是我的实现:
回复
flyxxxxx 2004-09-27
一个域表示为接口Field,每种域是Field的实现。将报文视为一个抽象的Message对象(读和写的未实现方法),每种报文是Message的一个子类。
interface Field{
public void read(InputStream is);
public void write(OutputStream os);
}
class StringField implements{//这里表示一个不定长的域
private int length;//长度位数
private String value;
public IntField(int length){
this.length=length;
}
public void read(IntpuStream is){
byte[] lengthBytes=new byte[length];
is.read(b,0,length);//读取长度位
int len=Integer.parseInt(new String(lengthBytes));//数据位实际长度
byte[] b=new byte[len];
is.read(b,0,len);
value=new String(b);//实际数据
}//写入方法就不写了
}
每个Message的实现和这差不多,只是按一定顺序组装Field
最后,在得到InputStream或OutputStream后,先读写头部分,确定它是什么具体的Message子类,实现这个子类,调用Message的读写方法
回复
oicqren 2004-09-27
谁能说说如何解析和组装8583报文,问题的重点不是如何通讯。
回复
dlglmf 2004-09-24
nio引进了非阻塞通信,和通道,效率高了不少
回复
gsen 2004-09-24
干吗非要用nio,普通的socket编程就可以啊
回复
oicqren 2004-09-24
哪位高手还能做进一步解答?
回复
oicqren 2004-09-23
这样好像只是解决了通讯问题,报文的组装和解析你还是没说呀?
回复
flyxxxxx 2004-09-22
只能用1.3,那就用java.net包中的ServerSocket和Socket,上面的地址也有关于这方面的教程
回复
oicqren 2004-09-22
NIO是jdk1.4的核心组件吗?如果我的项目中只允许使用1.3,有没有替代NIO的开源项目或者jdk其他核心组件?请赐教...
我这两天就在解决这个问题,如果此问题解决的好,分数全部加给你。
回复
flyxxxxx 2004-09-22
这里有一份NIO教程
http://www-900.ibm.com/developerWorks/cn/cnedu.nsf/java-onlinecourse-bytitle?OpenView&Count=500
回复
oicqren 2004-09-22
flyxxxx 能具体说说nio吗?
回复
flyxxxxx 2004-09-22
实际上就是Socket编程(如果是长连接,用java.nio可能更好),通过从Socket中读写字节来完成报文处理
回复
runi 2004-09-22
8583是啥!?
回复
加载更多回复
相关推荐
发帖
Web 开发
创建于2007-09-28

8.0w+

社区成员

Java Web 开发
申请成为版主
帖子事件
创建了帖子
2004-09-21 05:46
社区公告
暂无公告