银行业务需求实现一个8583的报文服务,实现后续业务。
然后作者在网上找了一个改造了一下。主要参考:
https://www.tangyuecan.com/2019/01/11/spring-boot%E9%9B%86%E6%88%90tcp-server/
Spring版本是4.3.8,
下面是代码说明
pom.xml
==========================================================
======================================================================
spring启动类,由于需要启动运行所以单独出来一个spring2.xml,只有sping.xml会导致无法运行启动方法。
package com.itstack.service;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TestInitializingBean222 {
@Autowired
private TcpSocket tcpsocket;
@PostConstruct // 无效的启动标签
public void initService() {
// 为了颜色一致,我们用管理Err输出
System.out.println("---------- 启动Socket线程池 ---------- ");
// TCPServer.moreserver(1234);
Thread serverthread = new Thread(tcpsocket);
serverthread.start();
// Lsy8583Util.exeMain();
}
// @Override
// public void afterPropertiesSet() throws Exception {
//
// //为了颜色一致,我们用管理Err输出
// System.err.println("---------- Spring自动加载 ---------- ");
// System.err.println("---------- 启动Netty线程池 ---------- ");
// System.out.println("---------- 启动Netty线程池 ---------- ");
//
// // TCPServer.moreserver(1234);
// }
}
======================================================================
对应的web.xml需要装载两个配置文件
======================================================================
8583报文解析类工具
package com.itstack.netty;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
/**
*
* 这是本人写的ISO8583报文工具类,包含了报文的组装和解析。
*
* 简单介绍下ISO8583。
* 这个东西说白了就是一种数据结构。我们定义一种规则把一堆东西放进去,再按照规则
* 把数据正确拿出来。这就是报文的实质。
*
* ISO8583报文的结构是:前面有16字节(128位)位图数据,后面就是数据。
* 报文最多有128个域(字段)。具体的一个报文不会有这么多,一般是几个域。
* 有哪几个就记录在位图中。而且域有定长和变长之分。
* 这些都是事先定义好的,具体可以看我写的properties定义文件.
*
* 位图转化成01字符串就是128个,如果某一位是1,代表这个域有值,然后按照properties定义的规则取值。
* 如果是0,则这个域没有值。
*
* 再说定长和变长。
* 定长域(定长比较好理解,一个字段规定是N位,那么字段值绝对不能超过N位,不足N位就在后面补空格)
* 变长域(变长域最后组装成的效果:例如变长3位,定义var3,这里的3是指长度值占3位,字段值是123456,最后结果就是006123456)
* 注意(变长的长度按照域值得字节长度计算,而不是按照域值字符串长度算!)
*
* 从网上不难找到ISO8583报文的介绍,这里就不多说了。
* 但是具体解析和组装的代码还真不好找,所以本人就写了一个让刚接触ISO8583报文的人更好入门。
*
*
*
* 解析的容器,我使用了Map,具体到工作中,还是要换成其他的容器的。
* 报文定义说明:config_8583.properties
* 例如
* FIELD031 = string,10
* FIELD032 = string,VAR2
*
* FIELD031是定长,长度是10
* FIELD032是变长,长度值占2位,也就是说长度值最大99,也就是域值最大长度99.
*
* @author lushuaiyin
*
*/
public class Lsy8583Util {
public static String packet_encoding="UTF-8";//报文编码 UTF-8 GBK
private static Map map8583Definition = null;// 8583报文128域定义器
static{
String basepath=Lsy8583Util.class.getClassLoader().getResource("").getPath();
System.out.println(basepath);
System.out.println("Lsy8583Util使用编码配置:[encoding:"+packet_encoding+"]");
Properties property = new Properties();
String path = basepath+"/config_8583.properties";
FileInputStream fis;
try {
fis = new FileInputStream(path);
property.load(fis);
Lsy8583Util.map8583Definition = new HashMap(property);
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 8583报文初始位图:128位01字符串
public static String getInitBitMap(){
String initBitMap =
"10000000" + "00000000" + "00000000" + "00000000"
+ "00000000" + "00000000" + "00000000" + "00000000"
+ "00000000" + "00000000" + "00000000" + "00000000"
+ "00000000" + "00000000" + "00000000" + "00000000";
return initBitMap;
}
/**
* @param args
*/
public static void main(String[] args) {
//sendTest();
exeMain() ;
}
public static void exeMain() {
try {
//***********************组装8583报文测试--start***********************//
TreeMap filedMap=new TreeMap();//报文域
filedMap.put("FIELD003", "1799");//交易码
filedMap.put("FIELD013", "2013-11-06");//交易日期
filedMap.put("FIELD008", "12345678901");//账号
filedMap.put("FIELD033", "aa索隆bb");//注意这个域是变长域!
filedMap.put("FIELD036", "123456");//注意这个域是变长域!
byte[] send=make8583(filedMap);
System.out.println("完成组装8583报文=="+new String(send,packet_encoding)+"==");
//***********************组装8583报文测试--end***********************//
Socket socket = new Socket("127.0.0.1", 9588);
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
outputStream.write(send);
outputStream.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, packet_encoding));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void sendTest() {
try {
//***********************组装8583报文测试--start***********************//
TreeMap filedMap=new TreeMap();//报文域
filedMap.put("FIELD003", "1799");//交易码
filedMap.put("FIELD013", "2013-11-06");//交易日期
filedMap.put("FIELD008", "12345678901");//账号
filedMap.put("FIELD033", "aa索隆bb");//注意这个域是变长域!
filedMap.put("FIELD036", "123456");//注意这个域是变长域!
byte[] send=make8583(filedMap);
System.out.println("完成组装8583报文=="+new String(send,packet_encoding)+"==");
//***********************组装8583报文测试--end***********************//
//***********************解析8583报文测试--start***********************//
Map back=analyze8583(send);
System.out.println("完成解析8583报文=="+back.toString()+"==");
//***********************解析8583报文测试--end***********************//
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/**
* 组装8583报文
* @param hm
* @return
*/
public static byte[] make8583(TreeMap filedMap){
byte[] whoe8583=null;
if(filedMap==null){
return null;
}
try {
String bitMap128=getInitBitMap();//获取初始化的128位图
//按照8583定义器格式化各个域的内容
Map all=formatValueTo8583(filedMap,bitMap128);
// 获取上送报文内容
whoe8583=getWhole8583Packet(all);
return whoe8583;
} catch (Exception e) {
e.printStackTrace();
}
return whoe8583;
}
/**
* 获取完整的8583报文体(128域)
* @param pacBody
* @return
*/
public static byte[] getWhole8583Packet(Map all){
if(all==null||all.get("formatedFiledMap")==null||all.get("bitMap128")==null){
return null;
}
try {
String bitMap128=(String)all.get("bitMap128");
// 128域位图二进制字符串转16位16进制
byte[] bitmaps= get16BitByteFromStr(bitMap128);
TreeMap pacBody=(TreeMap)all.get("formatedFiledMap");
StringBuffer last128=new StringBuffer();
Iterator it=pacBody.keySet().iterator();
for(;it.hasNext();){
String key=(String)it.next();
String value=(String)pacBody.get(key);
last128.append(value);
}
byte[] bitContent = last128.toString().getBytes(packet_encoding);//域值
//组装
byte[] package8583=null;
package8583=Lsy8583Util.arrayApend(package8583, bitmaps);
package8583=Lsy8583Util.arrayApend(package8583, bitContent);
return package8583;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Map formatValueTo8583(TreeMap filedMap,String bitMap128){
Map all=new HashMap();
TreeMap formatedFiledMap=new TreeMap();//格式化结果
if(filedMap!=null){
Iterator it=filedMap.keySet().iterator();
for(;it.hasNext();){
String fieldName=(String)it.next();//例如FIELD005
String fieldValue=(String)filedMap.get(fieldName);//字段值
try{
if (fieldValue == null) {
System.out.println("error:报文域 {" + fieldName + "}为空值");
fieldValue = "";
return null;
}
//将域值编码转换,保证报文编码统一
fieldValue=new String(fieldValue.getBytes(packet_encoding),packet_encoding);
// 数据域名称FIELD开头的为128域
if (fieldName.startsWith("FIELD") && fieldValue.length() >= 0) {
String fieldNo = fieldName.substring(5, 8);//例如005
// 组二进制位图串
bitMap128 = change16bitMapFlag(fieldNo, bitMap128);
// 获取域定义信息
String[] fieldDef = Lsy8583Util.map8583Definition.get("FIELD" + fieldNo).toString().split(",");
String defType=fieldDef[0];//类型定义例string
String defLen=fieldDef[1];//长度定义,例20
boolean isFixLen=true;//是否定长判断
if(defLen.startsWith("VAR")){//变长域
isFixLen=false;
defLen=defLen.substring(3);//获取VAR2后面的2
}
int fieldLen = fieldValue.getBytes(packet_encoding).length;//字段值得实际长度
// 判断是否为变长域
if (!isFixLen) {// 变长域(变长域最后组装成的效果:例如变长3位,定义var3,这里的3是指长度值占3位,字段值是123456,最后结果就是006123456)
int defLen1 = Integer.valueOf(defLen);
if (String.valueOf(fieldLen).length() > (10*defLen1)) {
System.out.println("error:字段" + fieldName + "的数据定义长度的长度为" + defLen + "位,长度不能超过"+(10*defLen1));
return null;
}else{
//将长度值组装入字段
fieldValue = getVaryLengthValue(fieldValue, defLen1) + fieldValue;
}
} else {//定长域(定长比较好理解,一个字段规定是N位,那么字段值绝对不能超过N位,不足N位就在后面补空格)
int defLen2 = Integer.valueOf(defLen);
if (fieldLen > defLen2) {
System.out.println("error:字段" + fieldName + "的数据定义长度为" + defLen + "位,长度不能超过"+defLen);
return null;
}else{
fieldValue=getFixFieldValue(fieldValue,defLen2);//定长处理
}
}
System.out.println("组装后报文域 {" + fieldName + "}==" + fieldValue+"==,域长度:"+fieldValue.getBytes(packet_encoding).length);
}
// 返回结果赋值
if (filedMap.containsKey(fieldName)) {
if (formatedFiledMap.containsKey(fieldName)) {
formatedFiledMap.remove(fieldName);
}
formatedFiledMap.put(fieldName, fieldValue);
} else {
System.out.println("error:" +fieldName + "配置文件中不存在!");
}
} catch (Exception e) {
e.printStackTrace();
}
}//end for
}
System.out.println("");
all.put("formatedFiledMap", formatedFiledMap);
all.put("bitMap128", bitMap128);
return all;
}
/**
* 解析8583报文
*
* @param content8583
*/
public static Map analyze8583(byte[] content8583) {
TreeMap filedMap=new TreeMap();
try {
// 取位图
byte[] bitMap16byte = new byte[16];
System.arraycopy(content8583, 0, bitMap16byte, 0, 16);
// 16位图转2进制位图128位字符串
String bitMap128Str = get16BitMapStr(bitMap16byte);
//记录当前位置,从位图后开始遍历取值
int pos = 16;
// 遍历128位图,取值。注意从FIELD002开始
for (int i = 1; i < bitMap128Str.length(); i++) {
String filedValue = "";//字段值
String filedName = "FIELD" + getNumThree((i+1));//FIELD005
if (bitMap128Str.charAt(i) == '1') {
// 获取域定义信息
String[] fieldDef = Lsy8583Util.map8583Definition.get(filedName).toString().split(",");
String defType=fieldDef[0];//类型定义例string
String defLen=fieldDef[1];//长度定义,例20
boolean isFixLen=true;//是否定长判断
if(defLen.startsWith("VAR")){//变长域
isFixLen=false;
defLen=defLen.substring(3);//获取VAR2后面的2
}
// 截取该域信息
if (!isFixLen) {//变长域
int defLen1 = Integer.valueOf(defLen);//VAR2后面的2
String realLen1=new String(content8583, pos, defLen1, packet_encoding);//报文中实际记录域长,例如16,023
int realAllLen=defLen1+Integer.valueOf(realLen1);//该字段总长度(包括长度值占的长度)
// filedValue = new String(content8583, pos+defLen1, Integer.valueOf(realLen1), packet_encoding);
byte[] filedValueByte=new byte[Integer.valueOf(realLen1)];
System.arraycopy(content8583, pos+defLen1, filedValueByte, 0, filedValueByte.length);
filedValue=new String(filedValueByte,packet_encoding);
pos += realAllLen;//记录当前位置
} else {//定长域
int defLen2 = Integer.valueOf(defLen);//长度值占的位数
filedValue = new String(content8583, pos, defLen2, packet_encoding);
pos += defLen2;//记录当前位置
}
filedMap.put(filedName, filedValue);
}
}//end for
} catch (Exception e) {
e.printStackTrace();
}
return filedMap;
}
//********************************以下是工具方法,有些没有使用到***********************************************************//
/**
* 复制字符
* @param str
* @param count
* @return
*/
public static String strCopy(String str,int count){
StringBuffer sb = new StringBuffer();
for(int i=0;i < count;i++){
sb.append(str);
}
return sb.toString();
}
/**
* 将setContent放入set(考虑到数组越界)
* @param set
* @param setContent
* @return
*/
public static byte[] setToByte(byte[] set,byte[] setContent){
byte[] res=new byte[set.length];
if(set==null||setContent==null){
}else{
if(set.length
}else{
System.arraycopy(setContent, 0, res, 0, setContent.length);
}
}
return res;
}
public static byte[] setToByte(byte[] set,String setContentStr){
byte[] res=new byte[set.length];
byte[] setContent;
try {
setContent = setContentStr.getBytes(packet_encoding);
res=setToByte(res,setContent);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return res;
}
public static String getPacketLen(int len){
String res="";
String lenStr=String.valueOf(len);
int lenC=4-lenStr.length();
res=strCopy("0",lenC)+lenStr;
return res;
}
public static String getPacketLen(String lenStr){
String res="";
if(lenStr==null){
}else{
res=getPacketLen(Integer.valueOf(lenStr));
}
return res;
}
/**
* 返回a和b的组合,实现累加功能
* @param a
* @param b
* @return
*/
public static byte[] arrayApend(byte[] a,byte[] b){
int a_len=(a==null?0:a.length);
int b_len=(b==null?0:b.length);
byte[] c=new byte[a_len+b_len];
if(a_len==0&&b_len==0){
return null;
}else if(a_len==0){
System.arraycopy(b, 0, c, 0, b.length);
}else if(b_len==0){
System.arraycopy(a, 0, c, 0, a.length);
}else{
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
}
return c;
}
/**
* 改变128位图中的标志为1
* @param fieldNo
* @param res
* @return
*/
public static String change16bitMapFlag(String fieldNo, String res) {
int indexNo=Integer.parseInt(fieldNo);
res = res.substring(0, indexNo-1) + "1" + res.substring(indexNo);
return res;
}
/**
* 位图操作
*
* 把16位图的字节数组转化成128位01字符串
* @param packet_header_map
* @return
*/
public static String get16BitMapStr(byte[] bitMap16){
String bitMap128 = "";
// 16位图转2进制位图128位字符串
for (int i = 0; i < bitMap16.length; i++) {
int bc = bitMap16[i];
bc=(bc<0)?(bc+256):bc;
String bitnaryStr=Integer.toBinaryString(bc);//二进制字符串
// 左补零,保证是8位
String rightBitnaryStr = strCopy("0",Math.abs(8-bitnaryStr.length())) + bitnaryStr;//位图二进制字符串
// 先去除多余的零,然后组装128域二进制字符串
bitMap128+=rightBitnaryStr;
}
return bitMap128;
}
/**
* 位图操作
*
* 把128位01字符串转化成16位图的字节数组
* @param packet_header_map
* @return
*/
public static byte[] get16BitByteFromStr(String str_128){
byte[] bit16=new byte[16];
try {
if(str_128==null||str_128.length()!=128){
return null;
}
// 128域位图二进制字符串转16位16进制
byte[] tmp=str_128.getBytes(packet_encoding);
int weight;//权重
byte[] strout = new byte[128];
int i, j, w = 0;
for (i = 0; i < 16; i++) {
weight = 0x0080;
for (j = 0; j < 8; j++) {
strout[i] += ((tmp[w]) - '0') * weight;
weight /= 2;
w++;
}
bit16[i] = strout[i];
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return bit16;
}
/**
* 从完整的8583报文中获取位图(16字节数组)
* @param packet
* @return
*/
public static byte[] getPacketHeaderMap(byte[] packet){
byte[] packet_header_map = new byte[16];
if(packet==null||packet.length<16){
return null;
}
for(int i=0;i<16;i++){
packet_header_map[i]=packet[i];
}
return packet_header_map;
}
/**
* 从完整的8583报文中获取16位图,转化成128位的01字符串
*
* @param content8583
* @return
*/
public static String get16BitMapFrom8583Byte(byte[] content8583){
// 取位图
byte[] bitMap16 = getPacketHeaderMap(content8583);
// 16位图转2进制位图128位字符串
String bitMap128 = get16BitMapStr(bitMap16);
return bitMap128;
}
//返回字段号码,例如005
public static String getNumThree(int i){
String len="";
String iStr=String.valueOf(i);
len=strCopy("0",3-iStr.length())+iStr;
return len;
}
/**
* 获取字符串变长值
* @param valueStr
* @param defLen
* 例如getFixLengthValue("12345678", 2)返回08
* 例如getFixLengthValue("12345678", 3)返回008
*
* 注意变长长度的计算:
* 长度的判断使用转化后的字节数组长度,因为中文在不同的编码方式下,长度是不同的,GBK是2,UTF-8是3,按字符创长度算就是1.
* 解析报文是按照字节来解析的,所以长度以字节长度为准,防止中文带来乱码。
*
* 比如一个变长域:aa索隆bb,如果按照字符串计算长度那么就是6,最后是06aa索隆bb。
* 这样在解析时按照字节解析长度就乱了,因为按照GBK字节解析,一个汉字占2,按照UTF-8解析,一个汉字占3.
* 所以在计算时必须按照字节长度为准!按照我们设置的UTF-8编码结果就是10aa索隆bb.
* 这样在解析时长度正好是10,也就不会乱了。
* @return
*/
public static String getVaryLengthValue(String valueStr,int defLen){
return getVaryLengthValue(valueStr,defLen,packet_encoding);
}
public static String getVaryLengthValue(String valueStr,int defLen,String encoding){
String fixLen="";
try{
if(valueStr==null){
return strCopy("0",defLen);
}else{
byte[] valueStrByte=null;
//这里最好指定编码,不使用平台默认编码
if(encoding==null||encoding.trim().equals("")){
valueStrByte=valueStr.getBytes();
}else{
valueStrByte=valueStr.getBytes(encoding);
}
//长度的判断使用转化后的字节数组长度,因为中文在不同的编码方式下,长度是不同的,GBK是2,UTF-8是3,按字符创长度算就是1.
//解析报文是按照字节来解析的,所以长度以字节长度为准,防止中文带来乱码
if(valueStrByte.length>(10*defLen)){
return null;
}else{
int len=valueStrByte.length;//字段实际长度
String len1=String.valueOf(len);
fixLen=strCopy("0",(defLen-len1.length()))+len1;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return fixLen;
}
/**
* 将字段值做定长处理,不足定长则在后面补空格
* @param valueStr
* @param defLen
* @return
*/
public static String getFixFieldValue(String valueStr,int defLen){
return getFixFieldValue(valueStr,defLen,packet_encoding);
}
public static String getFixFieldValue(String valueStr,int defLen,String encoding){
String fixLen="";
try {
if(valueStr==null){
return strCopy(" ",defLen);
}else{
byte[] valueStrByte=null;
//这里最好指定编码,不使用平台默认编码
if(encoding==null||encoding.trim().equals("")){
valueStrByte=valueStr.getBytes();
}else{
valueStrByte=valueStr.getBytes(encoding);
}
//长度的判断使用转化后的字节数组长度,因为中文在不同的编码方式下,长度是不同的,GBK是2,UTF-8是3,按字符创长度算就是1.
//解析报文是按照字节来解析的,所以长度以字节长度为准,防止中文带来乱码
if(valueStrByte.length>defLen){
return null;
}else{
fixLen=valueStr+strCopy(" ",defLen-valueStrByte.length);
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return fixLen;
}
public static String getPacket_encoding() {
return packet_encoding;
}
public static void setPacket_encoding(String packet_encoding) {
Lsy8583Util.packet_encoding = packet_encoding;
}
public static Map getMap8583Definition() {
return map8583Definition;
}
public static void setMap8583Definition(Map map8583Definition) {
Lsy8583Util.map8583Definition = map8583Definition;
}
}
======================================================
客户端测试类,发送报文
package com.itstack.netty;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.TreeMap;
public class TestClient {
/**
* @param args
*/
public static void main(String[] args) {
exeMain() ;
}
public static void exeMain() {
try {
//***********************组装8583报文测试--start***********************//
TreeMap filedMap=new TreeMap();//报文域
filedMap.put("FIELD003", "1799");//交易码
filedMap.put("FIELD013", "2013-11-06");//交易日期
filedMap.put("FIELD008", "12345678901");//账号
filedMap.put("FIELD033", "aa索隆bb");//注意这个域是变长域!
filedMap.put("FIELD036", "123456");//注意这个域是变长域!
byte[] send=Lsy8583Util.make8583(filedMap);
System.out.println("完成组装8583报文=="+new String(send,"UTF-8")+"==");
//***********************组装8583报文测试--end***********************//
Socket socket = new Socket("127.0.0.1", 9588);
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
outputStream.write(send);
outputStream.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
======================================================
业务类
package com.itstack.service;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.TreeMap;
import org.springframework.stereotype.Service;
import com.itstack.netty.Lsy8583Util;
@Service
public class DataAnalysis {
/**
* 解析数据包类
* @param buffer
* @param socket
*/
public void Analysis(byte[] buffer, Socket socket) {
// TODO Auto-generated method stub
System.out.println("收到线程发送的消息");
try {
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
//byte[] out = Parser.wrap(req);
String input=new String (buffer);
System.out.println("消息:"+input);
Map back=Lsy8583Util.analyze8583(buffer);
System.out.println("完成解析8583报文=="+back.toString()+"==");
TreeMap filedMap=new TreeMap();//报文域
filedMap.put("FIELD003", "0000");//交易码
filedMap.put("FIELD033", "交易正常");//注意这个域是变长域!
byte[] out=Lsy8583Util.make8583(filedMap);
//byte[] out = "收到线程发送的消息".getBytes("utf-8");
outputStream.write(out);
outputStream.flush();
socket.close();
return;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
======================================================
package com.itstack.service;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Vector;
public class SocketReceive implements Runnable {
private Socket socket;
private Vector
public SocketReceive() {
}
public SocketReceive(Socket socket, Vector
this.socket = socket;
allclients = clients;
}
@Override
public void run() {
while (true) {
if (null == socket) {
if (allclients.contains(socket)) {
allclients.remove(socket);
}
return;
}
boolean isClosed = socket.isClosed();
if (isClosed) {
if (allclients.contains(socket)) {
allclients.remove(socket);
}
return;
}
try {
DataInputStream in = new DataInputStream(socket.getInputStream());
byte[] buffer = new byte[1024 * 4];
if (in.read(buffer) == -1) {
if (allclients.contains(socket)) {
allclients.remove(socket);
}
return;
}
//DataAnalysis dataanalysis = SpringUtil.getBean(DataAnalysis.class);
DataAnalysis dataanalysis = new DataAnalysis();
dataanalysis.Analysis(buffer, socket);
} catch (IOException e) {
System.out.println(e);
if (allclients.contains(socket)) {
allclients.remove(socket);
}
try {
socket.close();
return;
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
return;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
================================================================
package com.itstack.service;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.springframework.stereotype.Component;
@Component
public class TcpSocket implements Runnable {
private Integer Port;
private ServerSocket Server;
private ExecutorService ThreadPool;
public Vector
public TcpSocket() {
try {
AllClients = new Vector<>();
AllClients.clear();
Port = 9588;
ThreadPool = Executors.newCachedThreadPool();
Server = new ServerSocket(Port);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
try {
Socket socket = Server.accept();
if (socket != null) {
SocketReceive socketReceive = new SocketReceive(socket, AllClients);
ThreadPool.submit(socketReceive);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
================================================================
config_8583.properties,配置8583报文的字段
FIELD002 = string,16
FIELD003 = string,4
FIELD004 = string,20
FIELD005 = string,20
FIELD006 = string,20
FIELD007 = string,10
FIELD008 = string,32
FIELD009 = string,3
FIELD010 = string,20
FIELD011 = string,6
FIELD012 = string,6
FIELD013 = string,10
FIELD014 = string,10
FIELD015 = string,10
FIELD016 = string,6
FIELD017 = string,6
FIELD018 = string,6
FIELD019 = string,6
FIELD020 = string,7
FIELD021 = string,7
FIELD022 = string,3
FIELD023 = string,3
FIELD024 = string,8
FIELD025 = string,5
FIELD026 = string,8
FIELD027 = string,1
FIELD028 = string,5
FIELD029 = string,5
FIELD030 = string,5
FIELD031 = string,10
FIELD032 = string,VAR2
FIELD033 = string,VAR2
FIELD034 = string,VAR2
FIELD035 = string,VAR2
FIELD036 = string,VAR3
FIELD037 = string,10
FIELD038 = string,4
FIELD039 = string,6
FIELD040 = string,2
FIELD041 = string,3
FIELD042 = string,16
FIELD043 = string,20
FIELD044 = string,VAR2
FIELD045 = string,VAR2
FIELD046 = string,VAR3
FIELD047 = string,VAR3
FIELD048 = string,VAR3
FIELD049 = string,3
FIELD050 = string,VAR3
FIELD051 = string,VAR3
FIELD052 = string,16
FIELD053 = string,VAR2
FIELD054 = string,VAR3
FIELD055 = string,VAR3
FIELD056 = string,VAR3
FIELD057 = string,VAR3
FIELD058 = string,VAR3
FIELD059 = string,VAR3
FIELD060 = string,VAR3
FIELD061 = string,VAR3
FIELD062 = string,VAR3
FIELD063 = string,VAR3
FIELD064 = string,16
FIELD065 = string,2
FIELD066 = string,1
FIELD067 = string,2
FIELD068 = string,16
FIELD069 = string,16
FIELD070 = string,3
FIELD071 = string,4
FIELD072 = string,2
FIELD073 = string,10
FIELD074 = string,10
FIELD075 = string,22
FIELD076 = string,17
FIELD077 = string,32
FIELD078 = string,VAR3
FIELD079 = string,6
FIELD080 = string,32
FIELD081 = string,32
FIELD082 = string,4
FIELD083 = string,4
FIELD084 = string,6
FIELD085 = string,15
FIELD086 = string,20
FIELD087 = string,20
FIELD088 = string,20
FIELD089 = string,6
FIELD090 = string,9
FIELD091 = string,9
FIELD092 = string,9
FIELD093 = string,VAR3
FIELD094 = string,2
FIELD095 = string,42
FIELD096 = string,8
FIELD097 = string,42
FIELD098 = string,3
FIELD099 = string,3
FIELD100 = string,80
FIELD101 = string,VAR3
FIELD102 = string,80
FIELD103 = string,80
FIELD104 = string,VAR3
FIELD105 = string,VAR3
FIELD106 = string,VAR3
FIELD107 = string,VAR3
FIELD108 = string,2
FIELD109 = string,VAR3
FIELD110 = string,9
FIELD111 = string,VAR3
FIELD112 = string,VAR3
FIELD113 = string,VAR3
FIELD114 = string,VAR3
FIELD115 = string,3
FIELD116 = string,VAR3
FIELD117 = string,VAR3
FIELD118 = string,VAR3
FIELD119 = string,VAR3
FIELD120 = string,VAR3
FIELD121 = string,32
FIELD122 = string,VAR3
FIELD123 = string,VAR3
FIELD124 = string,VAR3
FIELD125 = string,VAR3
FIELD126 = string,VAR3
FIELD127 = string,VAR3
FIELD128 = string,8
================================================================
全部源码下载地址:
https://download.csdn.net/download/rishengcsdn/11250548
Netty版本的代码:
https://download.csdn.net/my/uploads
================================================================
项目部署到tomcat8,启动后,会侦听9588端口,然后运行TestClient程序发送报文
运行结果:
/D:/workSpaceFujian/8583Server/target/classes/
Lsy8583Util使用编码配置:[encoding:UTF-8]
组装后报文域 {FIELD003}==1799==,域长度:4
组装后报文域 {FIELD008}==12345678901 ==,域长度:32
组装后报文域 {FIELD013}==2013-11-06==,域长度:10
组装后报文域 {FIELD033}==10aa索隆bb==,域长度:12
组装后报文域 {FIELD036}==006123456==,域长度:9
完成组装8583报文==�
服务端控制台输出:
收到线程发送的消息
消息:�
/D:/workSpaceFujian/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/8583Server/WEB-INF/classes/
Lsy8583Util使用编码配置:[encoding:UTF-8]
完成解析8583报文=={FIELD003=1799, FIELD008=12345678901 , FIELD013=2013-11-06, FIELD033=aa索隆bb, FIELD036=123456}==
组装后报文域 {FIELD003}==0000==,域长度:4
组装后报文域 {FIELD033}==12交易正常==,域长度:14