中间件服务实践

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 = 以上是关于中间件服务实践的主要内容,如果未能解决你的问题,请参考以下文章

[实践篇]13.18 Qnx进程管理slm学习笔记

Mycat数据库中间件上手实践及分布式事务和读写分离实现

海盗中间件:美团服务体验平台对接业务数据的最佳实践

海盗中间件:美团服务体验平台对接业务数据的最佳实践

喜马拉雅 Apache RocketMQ 消息治理实践

重新整理 .net core 实践篇—————静态中间件[二十一]