背景:部标GPS通讯底层全部改造成基于Netty服务器实现的,现将Mina的依赖移除,修改过程中有用到缓冲区的读写。现做了如下修改:
原有基于Mina的IoBuffer对字节读写封装代码如下:
1 package com.hns.gps.gw.jt808.protocol; 2 3 import com.hns.gps.gw.jt808.utils.Tools; 4 import org.apache.log4j.Logger; 5 import org.apache.mina.core.buffer.IoBuffer; 6 7 import java.nio.charset.CharacterCodingException; 8 import java.nio.charset.Charset; 9 10 public class MyBuffer { 11 private Logger logger = Logger.getLogger(MyBuffer.class); 12 IoBuffer buff; 13 14 public MyBuffer() { 15 buff.setUseDirectBuffer(false); 16 buff = IoBuffer.allocate(1536); 17 buff.mark(); 18 } 19 20 public MyBuffer(int len) { 21 buff.setUseDirectBuffer(false); 22 buff = IoBuffer.allocate(len); 23 buff.mark(); 24 } 25 26 public MyBuffer(byte[] bytes) { 27 if (bytes.length > 1024) 28 buff = IoBuffer.allocate(bytes.length + 100); 29 else 30 buff = IoBuffer.allocate(1024); 31 buff.mark(); 32 buff.put(bytes); 33 buff.limit(bytes.length); 34 buff.reset(); 35 } 36 public MyBuffer(byte[] bytes, int start, int length) { 37 buff = IoBuffer.allocate(length); 38 buff.mark(); 39 buff.put(bytes, start, length); 40 buff.limit(length); 41 buff.reset(); 42 } 43 44 45 public void clear() { 46 buff.clear(); 47 buff.mark(); 48 } 49 50 public void put(byte a) { 51 buff.put(a); 52 } 53 54 public void put(long a) 55 { 56 buff.putLong(a); 57 } 58 59 public void put(short a) { 60 buff.putShort(a); 61 } 62 63 public void put(byte[] a) { 64 buff.put(a); 65 } 66 67 public boolean hasRemain() { 68 return buff.remaining() > 0; 69 } 70 71 public void put(int a) { 72 buff.putInt(a); 73 } 74 75 public void putShort(int a) { 76 buff.putShort((short) a); 77 } 78 79 public void put(String str) { 80 // US-ASCII 81 82 try { 83 byte[] b = str.getBytes("gbk"); 84 buff.put(b); 85 86 } catch (Exception e) { 87 // logger.error(e.getMessage(), e); 88 } 89 } 90 91 public void putBcd(String str, int length) 92 { 93 byte[] b = BcDToBytes(str,length); 94 buff.put(b); 95 } 96 97 98 public static String BytesToBcd(byte[] bytes, int start, int len) { 99 StringBuilder bcd = new StringBuilder(); 100 for (int m = 0; m < len; m++) { 101 bcd.append(String.format("%02X", bytes[start + m])); 102 } 103 return bcd.toString(); 104 } 105 106 public static byte[] BcDToBytes(String bcd, int len) { 107 bcd = bcd == null ? "" : bcd; 108 while (bcd.length() < len) { 109 bcd = "0" + bcd; 110 } 111 return Tools.HexString2Bytes(bcd); 112 } 113 114 public void put(String str, int len) { 115 byte[] result = new byte[len]; 116 try { 117 byte[] b = str.getBytes("gbk"); 118 119 System.arraycopy(b, 0, result, 0, b.length); 120 121 for (int m = b.length; m < len; m++) { 122 result[m] = 0; 123 } 124 buff.put(result); 125 126 } catch (Exception e) { 127 //logger.error(e.getMessage(), e); 128 } 129 } 130 131 public byte get() { 132 return buff.get(); 133 } 134 135 public byte[] gets(int len) { 136 byte[] data = new byte[len]; 137 buff.get(data); 138 return data; 139 } 140 141 public int getInt() { 142 return buff.getInt(); 143 } 144 145 public short getShort() { 146 return buff.getShort(); 147 } 148 149 public long getLong() { 150 return buff.getLong(); 151 } 152 153 // 将data字节型数据转换为0~65535 (0xFFFF 即 WORD)。 154 public int getUnsignedShort() { 155 short t = buff.getShort(); 156 return t & 0xffff; 157 } 158 159 // 将data字节型数据转换为0~255 (0xFF 即BYTE)。 160 public int getUnsignedByte() { 161 return buff.get() & 0x0FF; 162 } 163 164 public long getUnsignedInt() { 165 return buff.getInt() & 0x0FFFFFFFF; 166 } 167 168 public String getString() { 169 try { 170 String strTemp = buff 171 .getString(Charset.forName("GBK").newDecoder()); 172 return strTemp; 173 } catch (CharacterCodingException e) { 174 e.printStackTrace(); 175 } 176 return ""; 177 } 178 179 public String getString(int len) { 180 try { 181 String strTemp = buff.getString(len, Charset.forName("GBK") 182 .newDecoder()); 183 return strTemp; 184 } catch (CharacterCodingException e) { 185 e.printStackTrace(); 186 gets(len); 187 } 188 return ""; 189 } 190 191 public String getBcdString(int len) { 192 byte[] bytes = this.gets(len); 193 StringBuilder bcd = new StringBuilder(); 194 for (int m = 0; m < len; m++) { 195 bcd.append(String.format("%02X", bytes[m])); 196 } 197 return bcd.toString(); 198 } 199 200 public byte[] array() { 201 int pos = buff.position(); 202 byte[] data = new byte[pos]; 203 buff.reset(); 204 buff.get(data); 205 return data; 206 } 207 208 public static void main(String[] args) { 209 210 IoBuffer ib = IoBuffer.allocate(1024); 211 ib.mark(); 212 ib.put((byte) 128); 213 ib.reset(); 214 // byte b = ib.get(); 215 // int x = b& 0xff; 216 short x = ib.getUnsigned(); 217 218 short y = ib.getUnsigned(0); 219 220 System.out.println("" + x + "," + y); 221 } 222 223 }
后修改成Netty版的ByteBuffer操作实现如下:
1 package com.hns.gps.gw.jt808.protocol; 2 3 import com.hns.gps.gw.jt808.utils.Tools; 4 import io.netty.buffer.ByteBuf; 5 import io.netty.buffer.ByteBufAllocator; 6 import io.netty.util.ReferenceCountUtil; 7 import io.netty.util.ResourceLeakDetector; 8 import org.apache.log4j.Logger; 9 10 import java.io.UnsupportedEncodingException; 11 import java.nio.charset.Charset; 12 13 /** 14 * ByteBuffer缓冲区,用Netty实现 15 * 16 * @author linys 17 * @create 2018-06-12 18 * @since 1.0.0 19 */ 20 public class ByteBuffer { 21 private Logger logger = Logger.getLogger(ByteBuffer.class); 22 protected ByteBuf buff; 23 24 public ByteBuffer() { 25 buff = ByteBufAllocator.DEFAULT.ioBuffer(1536); 26 //为了找到ByteBuff没有被释放的原因 (上线关闭) 27 ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); 28 } 29 30 public ByteBuffer(byte[] bytes) { 31 buff = ByteBufAllocator.DEFAULT.ioBuffer(bytes.length); 32 buff.writeBytes(bytes); 33 //为了找到ByteBuff没有被释放的原因 (上线关闭) 34 ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); 35 } 36 37 public ByteBuffer(byte[] bytes, int start, int length) { 38 buff = ByteBufAllocator.DEFAULT.ioBuffer(length); 39 buff.writeBytes(bytes, start, length); 40 //为了找到ByteBuff没有被释放的原因 (上线关闭) 41 ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); 42 } 43 44 public void clear() { 45 buff.clear(); 46 buff.markWriterIndex(); 47 buff.markReaderIndex(); 48 } 49 50 public void put(byte a) { 51 buff.writeByte(a); 52 } 53 54 public void put(long a) { 55 buff.writeLong(a); 56 } 57 58 public void put(short a) { 59 buff.writeShort(a); 60 } 61 62 public void put(byte[] a) { 63 buff.writeBytes(a); 64 } 65 66 public boolean hasRemain() { 67 return buff.isReadable(); 68 } 69 70 public void put(int a) { 71 buff.writeInt(a); 72 } 73 74 public void put(String str) { 75 // US-ASCII 76 try { 77 byte[] b = str.getBytes("gbk"); 78 buff.writeBytes(b); 79 } catch (UnsupportedEncodingException e) { 80 logger.error(e.getMessage(), e); 81 } 82 } 83 84 public String getBcdString(int len) { 85 byte[] bytes = this.gets(len); 86 StringBuilder bcd = new StringBuilder(); 87 for (int m = 0; m < len; m++) { 88 bcd.append(String.format("%02X", bytes[m])); 89 } 90 return bcd.toString(); 91 } 92 93 public void putBcd(String str, int length) { 94 byte[] b = BcDToBytes(str, length); 95 buff.writeBytes(b); 96 } 97 98 public static byte[] BcDToBytes(String bcd, int len) { 99 bcd = bcd == null ? "" : bcd; 100 while (bcd.length() < len) { 101 bcd = "0" + bcd; 102 } 103 return Tools.HexString2Bytes(bcd); 104 } 105 106 public static String BytesToBcd(byte[] bytes, int start, int len) { 107 StringBuilder bcd = new StringBuilder(); 108 for (int m = 0; m < len; m++) { 109 bcd.append(String.format("%02X", bytes[start + m])); 110 } 111 return bcd.toString(); 112 } 113 114 public void put(String str, int len) { 115 byte[] result = new byte[len]; 116 try { 117 byte[] b = str.getBytes("gbk"); 118 System.arraycopy(b,0, result,0, b.length); 119 for (int m = b.length; m < len; m++) { 120 result[m] = 0; //不够位补0 121 } 122 buff.writeBytes(result); 123 } catch (UnsupportedEncodingException e) { 124 logger.error(e.getMessage(), e); 125 } 126 } 127 128 public byte get() { 129 return buff.readByte(); 130 } 131 132 public short getShort() { 133 return buff.readShort(); 134 } 135 136 public int getInt() { 137 return buff.readInt(); 138 } 139 140 public long getLong() { 141 return buff.readLong(); 142 } 143 144 public double getDouble() { 145 return buff.readDouble(); 146 } 147 148 public byte[] gets(int len) { 149 byte[] data = new byte[len]; 150 buff.readBytes(data); 151 return data; 152 } 153 154 // 将data字节型数据转换为0~255 (0xFF 即BYTE)。 155 public short getUnsignedByte() { 156 return buff.readUnsignedByte(); 157 } 158 159 // 将data字节型数据转换为0~65535 (0xFFFF 即 WORD)。 160 public int getUnsignedShort() { 161 return buff.readUnsignedShort(); 162 } 163 164 public long getUnsignedInt() { 165 return buff.readUnsignedInt(); 166 } 167 168 public String getString() { 169 return buff.toString(Charset.forName("GBK")); 170 } 171 172 public String getString(int len) { 173 return buff.toString(0, len, Charset.forName("GBK")); 174 } 175 176 /** 177 * 转换成byte数组 178 * @return 179 */ 180 public byte[] toByteArray() { 181 int pos = buff.writerIndex(); 182 byte[] data = new byte[pos]; 183 buff.readBytes(data); 184 //再次调用重新从头读 185 buff.resetReaderIndex(); 186 return data; 187 } 188 189 /** 190 * 清空释放buff,在buff使用结束后调用 191 * @return 192 */ 193 public void release() { 194 this.clear(); 195 //释放缓冲区内存 196 ReferenceCountUtil.release(buff); 197 } 198 199 /** 200 * 转换成byte数组并清空释放buff,在buff使用结束后调用 201 * @return 202 */ 203 public byte[] toByteArrayAndRelease() { 204 int pos = buff.writerIndex(); 205 byte[] data = new byte[pos]; 206 buff.readBytes(data); 207 this.clear(); 208 //释放缓冲区内存 209 ReferenceCountUtil.release(buff); 210 return data; 211 } 212 213 214 }
总结:处理网络数据的项目中经常需要处理字节数据,Java的ByteBuffer很强大,对于NIO的ByteBuffer字节读写缓冲区操作,Mina和Netty都有封装,IoBuffer基于Java原生ByteBuffer封装而成,ByteBuff则是Netty自己独有的字节数据Buffer,Netty提供了更强大的封装并能实现零拷贝,更加方便我们操作字节缓冲区,推荐使用netty的ByteBuff!代码供大家对ByteBuff的封装参考。
文章封装的代码基于连接:
https://blog.csdn.net/alex_bean/article/details/51251015
https://blog.csdn.net/u010853261/article/details/53690780
https://www.cnblogs.com/zzt-lovelinlin/p/5292608.html