中间件服务实践
Posted Nipuream
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了中间件服务实践相关的知识,希望对你有一定的参考价值。
序言
16年年底,做了一个车载行业的项目,是基于公司的设备对出租车905协议解析保持与平台和设备其他进程保持通信的中间层服务。这个服务我们暂称为TaxiUsi,他和平台以及设备进程以及Client都有通信,且都是双向的,整体来说还是比较复杂的,由于机密问题,这里只给出整体的一个实现思路和流程,作为项目的总结,下面是整体的原理图:
可以看到,Client端和外设设备是通过Binder和TaxiUsi进行一个IPC操作,和905平台进行的是一个网络连接操作(Socket),而外设设备是通过蓝牙和硬件进行一个通信获取数据。而TaxiUsi的主要作用是和905平台一直保持一个通信的关系,并且对上报905平台数据一个组包,对下发数据包进行一个拆包,解包,传输的功能。可以看到TaxiUsi是连接三者之间的桥梁,是整个通信循环的心脏,对于整体项目而言,还是非常的重要的。
协议解析
首先来看看对905协议的解析,协议的解析非常的简单,但是有几点还是要引起我们的注意。
传输规则
一般网络传输大部分的协议都遵循大端模式和小端模式,什么是大小端模式呢?
所谓的大端模式(Big-endian),是指数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中;所谓的小端模式(Little-endian),是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。
其实大小端本义是pc内存保存数据的一种方式,比如0x8086一个十六进制的数据,占用两个字节的内存,如果采用大端保存数据的话,则是 86 80 ,发送数据则从低地址开始读取,则发送过去的是 8086,假如对方机器采用小端模式保存的话,则接受到的数据就是0x8680,显然这不是我们想要的结果。
转义规则
在网络传输的过程中,我们需要标识一个“标签”来标识一个完整数据包的头尾,这样,接受端才能正确的解包,得到想要的数据。一般的像905协议用的0x7E来标识,但是这又有个问题了,假如数据包中有个数据正好是0x7E,那该怎么办,接受端会错解包,这样会有违我们的初心了。这时,我们会有个转义的操作,如下所示:
0x7e ——-> 0x7d0x02
0x7d ——-> 0x7d0x01
但是这样处理,也会有一定的问题,什么问题呢?先来了解下整个数据包的格式:
每个数据包都会有一个校验位,比如接受端接受到数据,如果对数据包进行处理,得到的校验位是相同的,则是我们需要的数据包,否则就舍弃。那么传输的过程必须遵循以下规定:
发送消息时: 消息封装->计算并填充校验码->转义
接受消息时: 转义还原->验证校验码->解析消息对粘包、断包的处理
首先来理解下粘包和断包的概念,其实这两者没有太大的差别,只是网络传输过程中一种很常见的现象,为什么会出现这种现象呢?这得从我们TCP协议说起,了解TCP协议的童鞋应该知道,协议中有很多的算法,比如拥塞阻塞算法等,这些算法都是维持协议稳定和效率不可缺失的一部分,当我们客户端一直疯狂的向服务端发送数据,这时,服务端会将客户端发来的数据包缓存在一个队列中,服务端拿出来一个一个处理,然后在一起回复,那你可能还会问,那假如客户端一直不停的发数据,那服务端一直处理到什么时候才回复呢?这要根据TCP连接的滑动窗口的大小来确定了。还有种情况就是,当网络情况不好的时候,服务端发过来的数据客户端没有应答,那么服务端会重传,这时候也可能会导致粘包。那断包什么时候会发生呢?就是当回复的数据大小超过服务端缓存队列的大小,那么会分两次发送,这时中间的那个数据包可能断开了,或许可能那个数据包中的数据非常的重要,这就是断包产生的情况。其实,解决的方法也很简单,用一个队列或者链表一直将服务端发来的数据写入,我们另开启一条线程,一直从中读取即可。因为,当时项目中用到的是Mina框架,Mina框架中有解码器,我们只需继承它内置的解码器即可。如果对Mina不熟的可以看下它的官方文档 Apache Mina ,至于解码的代码就不贴出了。
解析处理
主要是对字节和Java基本类型之间的转换,比较简单,我也从网络搜集整理了一份。如下所示:
public class ParseUtil
private static final String TAG = "ParseUtil";
/**
* 字符串转换成指定长度的字符串
* @param value
* @param len
* @return
*/
public static String stringToString(String value,int len)
if(value == null)
value = "";
int length = value.length();
if(length > len)
value = value.substring(0, len);
else
for (int i = 0; i < (len-length); i++)
value = "0"+value;
return value;
/**
* 获取指定长度"\\0"结尾的数组转字符串
* @param data 字节数据包
* @param startIndex 开始位置
* @param length 截取长度
* @return 截取后的字节数据包
*/
public static byte[] byteToSubStringToByte(byte data[],int startIndex, int length)
try
String dataHex = ParseUtil.parseByte2HexStr(ParseUtil.byteTobyte(data, startIndex, length));
//用“00”结尾截取十六进制字符串
String[] strarr = replaceStr(dataHex,"00","##").split("##");
byte[] strbyte = null;
if(strarr.length == 0)
strbyte = new byte[0];
else
if("".equals(strarr[0]))
strbyte = new byte[0];
else
strbyte = parseHexStr2Byte(strarr[0]);
return strbyte;
catch (Exception e)
e.printStackTrace();
return null;
/**
* 将字符串转换成二进制
* @param str
* @return
*/
public static byte[] stringToByte(String str)
try
return (str+"\\0").getBytes("GBK");
catch (Exception e)
e.printStackTrace();
return null;
/**
* 将整数转换成二进制字节(先低字节后高字节)
* @param iSource
* @param iArrayLen
* @return
*/
public static byte[] int2Bytes(int iSource, int iArrayLen)
byte[] bLocalArr = new byte[iArrayLen];
for (int i = 0; (i < 4) && (i < iArrayLen); i++)
bLocalArr[i] = (byte) (iSource >> 8 * i & 0xFF);
return bLocalArr;
/**
* 获取整数转换成二进制字节
* @return
*/
public static String int2BytesStr(int iSource, int iArrayLen)
String str = parseByte2HexStr(int2Bytes(iSource,iArrayLen));
return str;
/**
* 获取指定长度字节数
* @param src
* @param startIndex
* @param length
* @return
*/
public static byte[] byteTobyte(byte[] src, int startIndex, int length)
byte[] des = new byte[length];
int i = 0;
for (int j = startIndex; i < length; ++j)
des[i] = src[j];
++i;
return des;
public static byte[] longToByteOne(long num)
byte[] b = new byte[1];
b[0] = (byte)(int)(num >>> 0);
return b;
/**将二进制转换成16进制
* @param buf
* @return
*/
public static String parseByte2HexStr(byte buf[])
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++)
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1)
hex = '0' + hex;
sb.append(hex.toUpperCase());
return sb.toString();
/**将16进制转换为二进制
* @param hexStr
* @return
*/
public static byte[] parseHexStr2Byte(String hexStr)
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length()/2];
for (int i = 0;i< hexStr.length()/2; i++)
int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
result[i] = (byte) (high * 16 + low);
return result;
/**
* 字符串转换成ascii的16进制
* @param value
* @return
*/
public static String stringToAsciiHexString(String value)
StringBuffer sbu = new StringBuffer();
char[] chars = value.toCharArray();
for (int i = 0; i < chars.length; i++)
sbu.append(Integer.toHexString((int)chars[i]));
return sbu.toString();
/**
* Bit转Byte
*/
public static byte BitToByte(String byteStr)
int re, len;
if (null == byteStr)
return 0;
len = byteStr.length();
if (len != 4 && len != 8)
return 0;
if (len == 8) // 8 bit处理
if (byteStr.charAt(0) == '0') // 正数
re = Integer.parseInt(byteStr, 2);
else // 负数
re = Integer.parseInt(byteStr, 2) - 256;
else //4 bit处理
re = Integer.parseInt(byteStr, 2);
return (byte) re;
/**
* 1) 报文的发送端需要将待发送报文的数据内容中(从版本号至校验位,包括版本号和校验位)出现的1002H转义为0x10100202,将出现的1003H转义为0x10100303。
* @param str
* @return
*/
public static byte[] tropeByte(String str,int type)
byte[] result = new byte[str.length()/2];
if(type == 1)
if(str.indexOf("1002")>=0)
str = str.replaceAll("1002", "10100202");
if(str.indexOf("1003")>=0)
str = str.replaceAll("1003", "10100203");
// if(str.indexOf("10")>=0)
// str = str.replaceAll("10", "1010");
//
str = replaceStr(str,"10", "1010");
result = ParseUtil.parseHexStr2Byte(str);
return result;
/**
* 为保证数据传输的透明,需对信息字段中出现的标志位进行转义处理,定义如下
* 7EH 《————》 7DH+02H;
* 7DH 《————》 7DH+01H;
* @param str
* @param type
* @return
*/
public static byte[] tropeYXByte(String str,int type)
byte[] result = new byte[str.length()/2];
if(type == 1)
str = replaceStr(str,"7D", "7D01");
str = replaceStr(str,"7E", "7D02");
// if(str.indexOf("7D")>=0)
// str = str.replaceAll("7D", "7D01");
//
//
// if(str.indexOf("7E")>=0)
// str = str.replaceAll("7E", "7D02");
//
str = replaceStr(str,"10", "1010");
result = ParseUtil.parseHexStr2Byte(str);
return result;
/**
* 转义操作
* @param str
* @param thq
* @param thh
* @return
*/
public static String replaceStr(String str,String thq,String thh)
StringBuffer des = new StringBuffer();
String s = "";
str = str+" ";
for(int i=0;i< str.length();i++)
if(i%2==0)
if(s.equals(thq))
s = thh;
des.append(s);
s = "";
s = s+str.charAt(i);
else
s = s+str.charAt(i);
return des.toString();
/**
* 转义操作(2个字符转4个字符)
* @param str
* @param thq
* @param thh
* @return
*/
public static String replaceTwoToFour(String str,String thq,String thh)
StringBuffer des = new StringBuffer();
String s = "";
str = str+" ";
for(int i=0;i< str.length();i++)
if(i%2==0)
if(s.equals(thq))
s = thh;
des.append(s);
s = "";
s = s+str.charAt(i);
else
s = s+str.charAt(i);
return des.toString();
/**
* 4个字符转2个字符
* @param data
* @param thq
* @param thh
* @return
*/
public static String replaceFourToTwo(String data,String thq,String thh)
StringBuffer dataBuffer = new StringBuffer();
for(int i=0;i< data.length();i+=2)
String dStr = data.substring(i, i+2);
dataBuffer.append(dStr);
String desc = dataBuffer.toString();
if(desc.endsWith(thq))
dataBuffer = new StringBuffer();
desc = desc.substring(0, desc.length()-4);
dataBuffer.append(desc);
dataBuffer.append("##");
return dataBuffer.toString().replaceAll("##", thh);
/**
* 对DTU协议进行逆转义(1010转10)
* @param bytes
* @return
*/
public static byte[] dtuTransferredMeaning(byte[] bytes)
StringBuffer des = new StringBuffer();
String str = "";
for (int j = 0; j < bytes.length; j++)
String hex = Integer.toHexString(bytes[j] & 0xFF).toUpperCase();
if (hex.length() == 1)
hex = '0' + hex;
if(hex.equals("10"))
str = str+hex;
if(str.indexOf("1010")>=0)
str = str.replaceAll("1010", "10");
des.append(str);
str = "";
else
if(str.indexOf("1010")>=0)
str = str.replaceAll("1010", "10");
des.append(str);
str = "";
des.append(hex);
return ParseUtil.parseHexStr2Byte(des.toString());
/**
* @param bytes
* @return
*/
public static byte[] taximeterToplightReversal(byte[] bytes)
String str = parseByte2HexStr(bytes);
str = str.replaceAll("10100202", "1002").replaceAll("10100303", "1003");
return parseHexStr2Byte(str);
/**
* 转义
* @param bytes
* @return
*/
public static byte[] yxReversal(byte[] bytes)
String data = parseByte2HexStr(bytes).toUpperCase();
if(data.indexOf("7D02")>=0)
data = replaceFourToTwo(data, "7D02", "7E");
if(data.indexOf("7D01")>=0)
data = replaceFourToTwo(data, "7D01", "7D");
return parseHexStr2Byte(data);
/**
* 9A转义
* @param bytes
* @param type
* @return
*/
public static byte[] data9AEscape(byte[] bytes,int type)
String data = parseByte2HexStr(bytes).toUpperCase();
if(type == 1)
if(data.indexOf("9D02")>=0)
data = replaceFourToTwo(data, "9D02", "9A");
if(data.indexOf("9D01")>=0)
data = replaceFourToTwo(data, "9D01", "9D");
return parseHexStr2Byte(data);
else
byte[] result = new byte[data.length()/2];
data = replaceTwoToFour(data,"9D", "9D01");
data = replaceTwoToFour(data,"9A", "9D02");
result = parseHexStr2Byte(data);
return result;
/**
* 高地位反相排序
* @param bytes
* @return
*/
public static byte[]sortToByte(byte[] bytes)
byte[] des = new byte[bytes.length];
int i = 0;
for (int j = bytes.length-1; j >=0; j--)
des[i] = bytes[j];
i++;
return des;
/**
* 异或运算和
* @param bytes
* @return
*/
public static byte[] byteOrbyte(byte[] bytes)
byte[] orbyte = new byte[1];
byte value = bytes[0];
for (int i = 1; i < bytes.length; i++)
value = (byte) (value^bytes[i]);
orbyte[0] = value;
return orbyte;
/**
*String的字符串转换成unicode的String
*/
public static String stringToUnicode(String strText) throws Exception
char c;
String strRet = "";
int intAsc;
String strHex;
for (int i = 0; i < strText.length(); i++)
c = strText.charAt(i);
intAsc = (int) c;
strHex = Integer.toHexString(intAsc);
if (intAsc > 128)
strRet += "\\\\u" + strHex;
else
// 低位在前面补00
strRet += "\\\\u00" + strHex;
return strRet;
/**
*unicode的String转换成String的字符串
*/
public static String unicodeToString(String hex)
int t = hex.length() / 6;
StringBuilder str = new StringBuilder();
for (int i = 0; i < t; i++)
String s = hex.substring(i * 6, (i + 1) * 6);
// 高位需要补上00再转
String s1 = s.substring(2, 4) + "00";
// 低位直接转
String s2 = s.substring(4);
// 将16进制的string转为int
int n = Integer.valueOf(s1, 16) + Integer.valueOf(s2, 16);
// 将int转换为字符
char[] chars = Character.toChars(n);
str.append(new String(chars));
return str.toString();
/**
* 得到经纬度的度、分(分+小数点后四位)
* @param latlng
* @param type 1 返回度 2 返回分 3 返回小数点后(1至2)两位 4 返回小数点(3至4)两位
* @return 十六进制字符串
*/
public static String getLatLng(double latlng,int type)
try
int reLatlng = 0;
double min = (latlng-(int)latlng)*60;
String minStr = String.valueOf(min).substring(String.valueOf(min).indexOf(".")+1, String.valueOf(min).length());
int size = minStr.length();
if(minStr.length()<4)
for (int i = 0; i < (4-size); i++)
minStr +="0";
switch (type)
case 1:
reLatlng = (int)latlng;
break;
case 2:
reLatlng = (int) ((latlng-(int)latlng)*60);
break;
case 3:
reLatlng = Integer.parseInt(minStr.substring(0, 2));
break;
case 4:
reLatlng = Integer.parseInt(minStr.substring(2, 4));
break;
default:
break;
return ParseUtil.parseByte2HexStr(ParseUtil.longToByteOne((reLatlng)));
catch (Exception e)
AppLog.e(ExceptionUtil.getInfo(e), e);
e.printStackTrace();
return "00";
/**
* 解码经纬度
* @param latlngbyte
* @return
*/
public static Double decoderLatlng(byte[] latlngbyte)
try
int no=0;
byte[] ad = ParseUtil.byteTobyte(latlngbyte, no, 1);
int adi = Integer.parseInt(ParseUtil.parseByte2HexStr(ad),16);
no+=1;
byte[] ac = ParseUtil.byteTobyte(latlngbyte, no, 1);
no+=1;
byte[] ac1 = ParseUtil.byteTobyte(latlngbyte, no, 1);
no+=1;
byte[] ac2 = ParseUtil.byteTobyte(latlngbyte, no, 1);
no+=1;
StringBuffer acBuffer = new StringBuffer();
acBuffer.append(Integer.parseInt(ParseUtil.parseByte2HexStr(ac),16));
acBuffer.append(Integer.parseInt(ParseUtil.parseByte2HexStr(ac1),16));
acBuffer.append(Integer.parseInt(ParseUtil.parseByte2HexStr(ac2),16));
Double acDouble = Double.parseDouble(acBuffer.toString())/10000;
Double latlng = adi + acDouble/60;
DecimalFormat df = new DecimalFormat("#.000000");
return Double.parseDouble(df.format(latlng));
catch (Exception e)
e.printStackTrace();
AppLog.e(ExceptionUtil.getInfo(e), e);
return 0.000000;
/**
* 得到16进制 年 月 日 时 分 秒
* @param formart
* @return 十六进制字符串
*/
public static String getDateTime(String formart)
String str = "00";
try
String systemdate = new SimpleDateFormat(formart).format(Calendar.getInstance().getTime());
str = parseByte2HexStr(longToByteOne(Long.parseLong(systemdate)));
catch (Exception e)
AppLog.e(ExceptionUtil.getInfo(e), e);
e.printStackTrace();
return str;
/**
* 将二进制转换成字符串
* @param src
* @param startIndex
* @param length
* @return
*/
public static String byteToString(byte[] src, int startIndex, int length)
byte[] des = new byte[length];
int i = 0;
for (int j = startIndex; i < length; ++j)
des[i] = src[j];
++i;
String str = null;
try
str= new String(des,"gb2312");
catch (UnsupportedEncodingException e)
// TODO Auto-generated catch block
AppLog.e(ExceptionUtil.getInfo(e), e);
e.printStackTrace();
return str.trim();
/**
* 数字字符串转ASCII码字符串
* @param content 转换内容
* @return 转换后的ASCII码字符串
*/
public static String StringToAsciiString(String content)
String result = "";
int max = content.length();
for (int i = 0; i < max; i++)
char c = content.charAt(i);
String b = Integer.toHexString(c);
result = result + b;
return result;
/**
* 字节转换成位
* @param bytes
* @return
*/
public static String byteTobit(byte[] bytes)
String str = "";
for (int j = 0; j < bytes.length; j++)
for(int i = 7; i >= 0; --i)
str +=(bytes[j] & (1 << i)) == 0 ? '0' : '1';
return str;
/**
* BCD码转为10进制串(阿拉伯数据)
* @param bytes 字节数组
* @return 转换后的字符串
*/
public static String bcd2Str(byte[] bytes)
StringBuffer temp=new StringBuffer(bytes.length*2);
for(int i=0;i<bytes.length;i++)
temp.append((byte)((bytes[i]& 0xf0)>>>4));
temp.append((byte)(bytes[i]& 0x0f));
return temp.toString().substring(0,1).equalsIgnoreCase("0")?temp.toString().substring(1):temp.toString();
/**
* 10进制串转为BCD码
* @param asc 字符串
* @return BCD码
*/
public static byte[] str2Bcd(String asc)
int len = asc.length();
int mod = len % 2;
if (mod != 0)
asc = "0" + asc;
len = asc.length();
byte abt[] = new byte[len];
if (len >= 2)
len = len / 2;
byte bbt[] = new byte[len];
abt = asc.getBytes();
int j, k;
for (int p = 0; p < asc.length()/2; p++)
if ( (abt[2 * p] >= '0') && (abt[2 * p] <= '9'))
j = abt[2 * p] - '0';
else if ( (abt[2 * p] >= 'a') && (abt[2 * p] <= 'z'))
j = abt[2 * p] - 'a' + 0x0a;
else
j = abt[2 * p] - 'A' + 0x0a;
if ( (abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9'))
k = abt[2 * p + 1] - '0';
else if ( (abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z'))
k = abt[2 * p + 1] - 'a' + 0x0a;
else
k = abt[2 * p + 1] - 'A' + 0x0a;
int a = (j << 4) + k;
byte b = (byte) a;
bbt[p] = b;
return bbt;
/**
* 转换成指定长度的字符串 少的部分以空格填充
* @param s
* @param fieldLength
* @return
*/
public static String appendSpaceRight(String s, int fieldLength)
if (s == null)
s = "";
String ret = s;
int stringLength = s.length();
if (stringLength < fieldLength)
for (int i = stringLength; i < fieldLength; ++i)
ret = ret + " ";
else if (stringLength > fieldLength)
ret = ret.substring(0, fieldLength);
return ret;
/**
* 转换成指定长度的字符串 少的部分以0填充
* @param s
* @param fieldLength
* @return
*/
public static String appendRight(String s, int fieldLength)
if (s == null)
s = "";
String ret = s;
int stringLength = s.getBytes().length;
if (stringLength < fieldLength)
for (int i = stringLength; i < fieldLength; ++i)
ret = ret + "0";
else if (stringLength > fieldLength)
ret = ret.substring(0, fieldLength);
return ret;
/**
* 返回指定长度的字节数组
* @param str
* @param len
* @return
*/
public static byte[] getByteToByte(String str,int len)
byte[] body = new byte[len];
int dstPos = 0;
//省域ID
System.arraycopy(str.getBytes(), 0, body, dstPos, str.getBytes().length);
return body;
// 将byte数组转换成InputStream
public static InputStream byteTOInputStream(byte[] in) throws Exception
ByteArrayInputStream is = new ByteArrayInputStream(in);
return is;
/**
* 字符串转换成十六进制字符串
*/
public static String str2HexStr(String str)
char[] chars = "0123456789ABCDEF".toCharArray();
StringBuilder sb = new StringBuilder("");
byte[] bs = str.getBytes();
int bit;
for (int i = 0; i < bs.length; i++)
bit = (bs[i] & 0x0f0) >> 4;
sb.append(chars[bit]);
bit = bs[i] & 0x0f;
sb.append(chars[bit]);
return sb.toString();
/**
* 十六进制转换字符串
*/
public static String hexStr2Str(String hexStr)
String str = "0123456789ABCDEF";
char[] hexs = hexStr.toCharArray();
byte[] bytes = new byte[hexStr.length() / 2];
int n;
for (int i = 0; i < bytes.length; i++)
n = str.indexOf(hexs[2 * i]) * 16;
n += str.indexOf(hexs[2 * i + 1]);
bytes[i] = (byte) (n & 0xff);
return new String(bytes);
public static char ascii2Char(int ASCII)
return (char) ASCII;
public static int char2ASCII(char c)
return (int) c;
/**
* 将 ascii转换成字符串
* @param ASCIIs
* @return
*/
public static String ascii2String(String ASCIIs)
String[] ASCIIss = ASCIIs.split(" ");
StringBuffer sb = new StringBuffer();
for (int i = 0; i < ASCIIss.length; i++)
sb.append((char) ascii2Char(Integer.parseInt(ASCIIss[i])));
return sb.toString();
/**
* byte——>String
* @param src
* @return
*/
public static String bytesToHexString(byte[] src)
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0)
return null;
for (int i = 以上是关于中间件服务实践的主要内容,如果未能解决你的问题,请参考以下文章