中间件服务实践

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YanghuiNipurean/article/details/68951459

序言

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 = 0; i < src.length; i++) {  
            int v = src[i] & 0xFF;  
            String hv = Integer.toHexString(v);  
            if (hv.length() < 2) {  
                stringBuilder.append(0);  
            }  
            stringBuilder.append(hv);  
        }  
        return stringBuilder.toString();  
    } 

    /**
     * 字符串编码转换的实现方法
     * @param str  待转换编码的字符串
     * @param newCharset 目标编码
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String changeCharset(String str, String newCharset)
            throws UnsupportedEncodingException {
        if (str != null) {
            //用默认字符编码解码字符串。
            byte[] bs = str.getBytes();
            //用新的字符编码生成字符串
            return new String(bs, newCharset);
        }
        return null;
    }

    /** 
     * 校验和 
     * @param msg 需要计算校验和的byte数组 
     * @param length 校验和位数 
     * @return 计算出的校验和数组 
     */  
    public static byte[] sumCheck(byte[] msg, int length) {  
        long mSum = 0;  
        byte[] mByte = new byte[length];  

        /** 逐Byte添加位数和 */  
        for (byte byteMsg : msg) {  
            long mNum = ((long)byteMsg >= 0) ? (long)byteMsg : ((long)byteMsg + 256);  
            mSum += mNum;  
        } /** end of for (byte byteMsg : msg) */  

        /** 位数和转化为Byte数组 */  
        for (int liv_Count = 0; liv_Count < length; liv_Count++) {  
            mByte[length - liv_Count - 1] = (byte)(mSum >> (liv_Count * 8) & 0xff);  
        }

        return mByte;  
    }

    /** 从字符串中获取数字*/
    public static String filtrateNumber(String text){
        if(text != null && !text.equals("")){
            String number = "";
            String regEx="[^0-9]";   
            Pattern p = Pattern.compile(regEx);   
            Matcher m = p.matcher(text);   
            number = m.replaceAll("").trim();
            return number;
        }else{
            return null;
        }
    }

    /**
     * 带小数点字符串转整数
     * @param str
     * @param num
     * @return
     */
    public static int stringToint(String str,int num){
        try {
            return (int) (Double.parseDouble(str)*num);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}


代码设计

分析完协议的解析,我们就要把重点放到如何去设计框架的组成和实现他们之间的通信。其实如何实现得要看他的所需的功能而定的,比如TaxiUsi必须要保持长连接和平台保持通信,所以用了Mina。

  • 基本框架

    其实,我这个项目就三个核心模块,一个网络通信模块,一个IPC远程接口模块,一个本地持久层模块(因为没有发送出去的数据要保存在数据库)。如下图所示:
    这里写图片描述

    从图中可以看出整体业务逻辑还是蛮复杂的,这个只是整个程序的框架图,下面考虑一些实现的难点。

  • 消息重传机制

    细心的你可能会发现图中有个MsgPackage,这是我对数据包的又一层封装,那为什么要封装呢,主要有两个目的,第一种可能网络情况不是很好,需要我们临时把消息写入数据库,等网络状态的时候再重新发送,还有种情况是平台下发数据需要我们回复的,这样很容易和我们主动上报的数据发生混淆,按照905协议,消息重传机制满足的公式为: f(x+1) = f(x) * (N+1),其中f(x+1)表示每次重传后的应答超时时间,N表示重传次数。我们需要考虑两种情况,一种是平台主动发送消息给TaxiUsi服务,如果我们顺利回复平台成功,则流程结束,如果回复失败,则将消息传递给消息队列,根据下次发送的时间间隔再次发送,第二种,是我们自己主动上报给平台消息,当发送成功的时候,我们同样需要将消息发送给消息队列,如果在指定时间内,平台回复我们了,我们再清除消息队列中对应的消息,如果发送失败了,则传送给平台失败,我们不需要处理,下面给出TaxiUsi主动发送给平台消息的逻辑处理图:
    这里写图片描述

  • 其他机制

    在网络传输过程中,连接断了是很正常的事情,我们要设计出一套能够快速响应并且低功耗的连接策略,比如什么时候重新连接,多长时间检测一次都是我们所需要考虑的事情,尽量使用最少的系统资源用到极致。还有在系统资源不足的情况下,或者内部因素导致的,比如异常等,导致线程挂掉了,那么我们还需要运行个后台线程,用于检测他们的生命状态,如果死亡,则立即重启。

猜你喜欢

转载自blog.csdn.net/YanghuiNipurean/article/details/68951459