背景:部标GPS通讯底层全部改造成基于Netty服务器实现的,现将Mina的依赖移除,修改过程中有用到缓冲区的读写。现做了如下修改:
原有基于Mina的IoBuffer对字节读写封装代码如下:
1package com.hns.gps.gw.jt808.protocol; 2 3import com.hns.gps.gw.jt808.utils.Tools; 4import org.apache.log4j.Logger; 5import org.apache.mina.core.buffer.IoBuffer; 6 7import java.nio.charset.CharacterCodingException; 8import java.nio.charset.Charset; 9 10publicclass MyBuffer { 11private Logger logger = Logger.getLogger(MyBuffer.class); 12 IoBuffer buff; 13 14public MyBuffer() { 15 buff.setUseDirectBuffer(false); 16 buff = IoBuffer.allocate(1536); 17 buff.mark(); 18 } 19 20public MyBuffer(int len) { 21 buff.setUseDirectBuffer(false); 22 buff = IoBuffer.allocate(len); 23 buff.mark(); 24 } 25 26public MyBuffer(byte[] bytes) { 27if (bytes.length > 1024) 28 buff = IoBuffer.allocate(bytes.length + 100); 29else 30 buff = IoBuffer.allocate(1024); 31 buff.mark(); 32 buff.put(bytes); 33 buff.limit(bytes.length); 34 buff.reset(); 35 } 36public 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 45publicvoid clear() { 46 buff.clear(); 47 buff.mark(); 48 } 49 50publicvoid put(byte a) { 51 buff.put(a); 52 } 53 54publicvoid put(long a) 55 { 56 buff.putLong(a); 57 } 58 59publicvoid put(short a) { 60 buff.putShort(a); 61 } 62 63publicvoid put(byte[] a) { 64 buff.put(a); 65 } 66 67publicboolean hasRemain() { 68return buff.remaining() > 0; 69 } 70 71publicvoid put(int a) { 72 buff.putInt(a); 73 } 74 75publicvoid putShort(int a) { 76 buff.putShort((short) a); 77 } 78 79publicvoid put(String str) { 80// US-ASCII 81 82try { 83byte[] b = str.getBytes("gbk"); 84 buff.put(b); 85 86 }catch (Exception e) { 87// logger.error(e.getMessage(), e); 88 } 89 } 90 91publicvoid putBcd(String str,int length) 92 { 93byte[] b = BcDToBytes(str,length); 94 buff.put(b); 95 } 96 97 98publicstatic String BytesToBcd(byte[] bytes,int start,int len) { 99 StringBuilder bcd =new StringBuilder();100for (int m = 0; m < len; m++) {101 bcd.append(String.format("%02X", bytes[start + m]));102 }103return bcd.toString();104 }105106publicstaticbyte[] BcDToBytes(String bcd,int len) {107 bcd = bcd ==null ? "" : bcd;108while (bcd.length() < len) {109 bcd = "0" + bcd;110 }111return Tools.HexString2Bytes(bcd);112 }113114publicvoid put(String str,int len) {115byte[] result =newbyte[len];116try {117byte[] b = str.getBytes("gbk");118119 System.arraycopy(b, 0, result, 0, b.length);120121for (int m = b.length; m < len; m++) {122 result[m] = 0;123 }124 buff.put(result);125126 }catch (Exception e) {127//logger.error(e.getMessage(), e);128 }129 }130131publicbyte get() {132return buff.get();133 }134135publicbyte[] gets(int len) {136byte[] data =newbyte[len];137 buff.get(data);138return data;139 }140141publicint getInt() {142return buff.getInt();143 }144145publicshort getShort() {146return buff.getShort();147 }148149publiclong getLong() {150return buff.getLong();151 }152153// 将data字节型数据转换为0~65535 (0xFFFF 即 WORD)。154publicint getUnsignedShort() {155short t = buff.getShort();156return t & 0xffff;157 }158159// 将data字节型数据转换为0~255 (0xFF 即BYTE)。160publicint getUnsignedByte() {161return buff.get() & 0x0FF;162 }163164publiclong getUnsignedInt() {165return buff.getInt() & 0x0FFFFFFFF;166 }167168public String getString() {169try {170 String strTemp = buff171 .getString(Charset.forName("GBK").newDecoder());172return strTemp;173 }catch (CharacterCodingException e) {174 e.printStackTrace();175 }176return "";177 }178179public String getString(int len) {180try {181 String strTemp = buff.getString(len, Charset.forName("GBK")182 .newDecoder());183return strTemp;184 }catch (CharacterCodingException e) {185 e.printStackTrace();186 gets(len);187 }188return "";189 }190191public String getBcdString(int len) {192byte[] bytes =this.gets(len);193 StringBuilder bcd =new StringBuilder();194for (int m = 0; m < len; m++) {195 bcd.append(String.format("%02X", bytes[m]));196 }197return bcd.toString();198 }199200publicbyte[] array() {201int pos = buff.position();202byte[] data =newbyte[pos];203 buff.reset();204 buff.get(data);205return data;206 }207208publicstaticvoid main(String[] args) {209210 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;216short x = ib.getUnsigned();217218short y = ib.getUnsigned(0);219220 System.out.println("" + x + "," + y);221 }222223 }
后修改成Netty版的ByteBuffer操作实现如下:
1package com.hns.gps.gw.jt808.protocol; 2 3import com.hns.gps.gw.jt808.utils.Tools; 4import io.netty.buffer.ByteBuf; 5import io.netty.buffer.ByteBufAllocator; 6import io.netty.util.ReferenceCountUtil; 7import io.netty.util.ResourceLeakDetector; 8import org.apache.log4j.Logger; 9 10import java.io.UnsupportedEncodingException; 11import java.nio.charset.Charset; 12 13/** 14 * ByteBuffer缓冲区,用Netty实现 15 * 16 *@author linys 17 * @create 2018-06-12 18 *@since 1.0.0 19*/ 20publicclass ByteBuffer { 21private Logger logger = Logger.getLogger(ByteBuffer.class); 22protected ByteBuf buff; 23 24public ByteBuffer() { 25 buff = ByteBufAllocator.DEFAULT.ioBuffer(1536); 26//为了找到ByteBuff没有被释放的原因 (上线关闭) 27 ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); 28 } 29 30public ByteBuffer(byte[] bytes) { 31 buff = ByteBufAllocator.DEFAULT.ioBuffer(bytes.length); 32 buff.writeBytes(bytes); 33//为了找到ByteBuff没有被释放的原因 (上线关闭) 34 ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); 35 } 36 37public 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 44publicvoid clear() { 45 buff.clear(); 46 buff.markWriterIndex(); 47 buff.markReaderIndex(); 48 } 49 50publicvoid put(byte a) { 51 buff.writeByte(a); 52 } 53 54publicvoid put(long a) { 55 buff.writeLong(a); 56 } 57 58publicvoid put(short a) { 59 buff.writeShort(a); 60 } 61 62publicvoid put(byte[] a) { 63 buff.writeBytes(a); 64 } 65 66publicboolean hasRemain() { 67return buff.isReadable(); 68 } 69 70publicvoid put(int a) { 71 buff.writeInt(a); 72 } 73 74publicvoid put(String str) { 75// US-ASCII 76try { 77byte[] b = str.getBytes("gbk"); 78 buff.writeBytes(b); 79 }catch (UnsupportedEncodingException e) { 80 logger.error(e.getMessage(), e); 81 } 82 } 83 84public String getBcdString(int len) { 85byte[] bytes =this.gets(len); 86 StringBuilder bcd =new StringBuilder(); 87for (int m = 0; m < len; m++) { 88 bcd.append(String.format("%02X", bytes[m])); 89 } 90return bcd.toString(); 91 } 92 93publicvoid putBcd(String str,int length) { 94byte[] b = BcDToBytes(str, length); 95 buff.writeBytes(b); 96 } 97 98publicstaticbyte[] BcDToBytes(String bcd,int len) { 99 bcd = bcd ==null ? "" : bcd;100while (bcd.length() < len) {101 bcd = "0" + bcd;102 }103return Tools.HexString2Bytes(bcd);104 }105106publicstatic String BytesToBcd(byte[] bytes,int start,int len) {107 StringBuilder bcd =new StringBuilder();108for (int m = 0; m < len; m++) {109 bcd.append(String.format("%02X", bytes[start + m]));110 }111return bcd.toString();112 }113114publicvoid put(String str,int len) {115byte[] result =newbyte[len];116try {117byte[] b = str.getBytes("gbk");118 System.arraycopy(b,0, result,0, b.length);119for (int m = b.length; m < len; m++) {120 result[m] = 0;//不够位补0121 }122 buff.writeBytes(result);123 }catch (UnsupportedEncodingException e) {124 logger.error(e.getMessage(), e);125 }126 }127128publicbyte get() {129return buff.readByte();130 }131132publicshort getShort() {133return buff.readShort();134 }135136publicint getInt() {137return buff.readInt();138 }139140publiclong getLong() {141return buff.readLong();142 }143144publicdouble getDouble() {145return buff.readDouble();146 }147148publicbyte[] gets(int len) {149byte[] data =newbyte[len];150 buff.readBytes(data);151return data;152 }153154// 将data字节型数据转换为0~255 (0xFF 即BYTE)。155publicshort getUnsignedByte() {156return buff.readUnsignedByte();157 }158159// 将data字节型数据转换为0~65535 (0xFFFF 即 WORD)。160publicint getUnsignedShort() {161return buff.readUnsignedShort();162 }163164publiclong getUnsignedInt() {165return buff.readUnsignedInt();166 }167168public String getString() {169return buff.toString(Charset.forName("GBK"));170 }171172public String getString(int len) {173return buff.toString(0, len, Charset.forName("GBK"));174 }175176/**177 * 转换成byte数组178 *@return179*/180publicbyte[] toByteArray() {181int pos = buff.writerIndex();182byte[] data =newbyte[pos];183 buff.readBytes(data);184//再次调用重新从头读185 buff.resetReaderIndex();186return data;187 }188189/**190 * 清空释放buff,在buff使用结束后调用191 *@return192*/193publicvoid release() {194this.clear();195//释放缓冲区内存196 ReferenceCountUtil.release(buff);197 }198199/**200 * 转换成byte数组并清空释放buff,在buff使用结束后调用201 *@return202*/203publicbyte[] toByteArrayAndRelease() {204int pos = buff.writerIndex();205byte[] data =newbyte[pos];206 buff.readBytes(data);207this.clear();208//释放缓冲区内存209 ReferenceCountUtil.release(buff);210return data;211 }212213214 }
总结:处理网络数据的项目中经常需要处理字节数据,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
转载于:https://www.cnblogs.com/lys_013/p/9176037.html