ByteBuffer
a simple binary data processing tool
一個(gè)簡單的二進(jìn)制處理類
Github地址:https://github.com/itgowo/MiniTCPClient/blob/master/src/main/java/com/itgowo/tcp/me/ByteBuffer.java
在TCP長連接中解決粘包半包有用到漠烧,項(xiàng)目PackageMessage
一:故事
寫一個(gè)TCP長連接方案炉擅,遇到粘包分包問題价说,服務(wù)端于是用ByteArrayOutStream實(shí)現(xiàn)了遵堵,感覺太過于麻煩浑槽, 于是用java nio 的 ByteBuffer,但是不太靈活聋亡,最后用Netty的ByteBuf類壁顶,豁然開朗,盡然可以把代碼壓縮到這么少诺核,轉(zhuǎn)念一想抄肖,Android端怎么實(shí)現(xiàn)呢久信?畢竟引入Netty包太大,即使是部分代碼也很大漓摩。Nio的ByteBuffer呢裙士?遇見好用的自然看不上不太靈活的,于是寫了此類解決幌甘。
二:引入
目前將ByteBuffer和PackageMessage都放到了MiniTCPClient項(xiàng)目里潮售。
compile 'com.itgowo:MiniTCPClient:最新版本
三:功能介紹
Java Nio的ByteBuffer用起來不靈活(只說內(nèi)存中二進(jìn)制處理,MappedByteBuffer等不算),功能上也只是比Java Nio的ByteBuffer多了幾個(gè)锅风,正好我想用的就是多的這幾個(gè)酥诽,比如內(nèi)部數(shù)組是支持動(dòng)態(tài)擴(kuò)展的,默認(rèn)大小256皱埠,如果write超過容量會(huì)自動(dòng)擴(kuò)容肮帐。計(jì)算方法如下:
private void autoExpandCapacity(int addLength) {
if (writableBytes() < addLength) {
int newSize = writableBytes() + addLength;
int size = 0;
while (size < newSize) {
size += BUFFER_SIZE;
}
byte[] newBytes = new byte[size];
writeBytesToBytes(data, newBytes, 0);
data = newBytes;
}
}
Netty的CompositeByteBuf處理方式會(huì)把多個(gè)ByteBuf用list形式組織起來,每個(gè)ByteBuf都不會(huì)太大边器,Netty那套很值得學(xué)習(xí)训枢,我也只能學(xué)習(xí)皮毛而已。
我寫的這個(gè)ByteBuffer也支持銷毀已讀部分discardReadBytes()忘巧,獲取原始array()和獲取剩余可讀數(shù)據(jù)readableBytesArray()恒界,單獨(dú)讀寫int、byte或者long砚嘴,隨意移動(dòng)指針位置等十酣。
從數(shù)組拷貝上使用System.arraycopy(),效率比較有保證
四:簡單使用
ByteBuffer結(jié)構(gòu)
變量名 | 類型 | 說明 |
---|---|---|
readerIndex | Integer | 指針位置际长,即將讀取的位置 |
writerIndex | Integer | 指針位置耸采,即將寫入的位置 |
data | ByteArray | 原始數(shù)據(jù)數(shù)組 |
創(chuàng)建ByteBuffer
ByteBuffer buffer = ByteBuffer.newByteBuffer();
ByteBuffer buffer = ByteBuffer.newByteBuffer(int capacity)
capacity參數(shù)指定初始數(shù)組大小,默認(rèn)為256.
方法
方法名 | 參數(shù)一 | 參數(shù)二 | 返回值 | 說明 |
---|---|---|---|---|
newByteBuffer() | ByteBuffer | 創(chuàng)建新ByteBuffer工育,默認(rèn)大小256 | ||
newByteBuffer(int capacity) | 默認(rèn)大小 | ByteBuffer | 創(chuàng)建新ByteBuffer虾宇,大小為capacity | |
capacity() | int | 返回當(dāng)前最大容量 | ||
array() | ByteArray | 獲取原始數(shù)組,包含所有部分 | ||
clear() | ByteBuffer | 清理指針標(biāo)記如绸,狀態(tài)為剛創(chuàng)建狀態(tài)嘱朽,但是data數(shù)據(jù)不變,新數(shù)組會(huì)覆蓋舊數(shù)據(jù)怔接,除了array()獲取原始數(shù)組外無法得到舊數(shù)據(jù) | ||
discardReadBytes() | void | 刪除已讀部分燥翅,重新初始化數(shù)組 | ||
readerIndex(int position) | 重置指針位置 | ByteBuffer | 如果大于寫入位置,則可讀位置重置為寫入位置蜕提,readableBytes()結(jié)果則為0 | |
readerIndex() | int | 讀指針位置 | ||
writerIndex() | int | 寫指針位置 | ||
readableBytes() | int | 當(dāng)前可讀數(shù)據(jù)量,writerIndex - readerIndex | ||
writableBytes() | int | 當(dāng)前可寫入數(shù)據(jù)量靶端,每次觸發(fā)擴(kuò)容后都不一樣 | ||
read() | int | 讀取數(shù)據(jù)到byte谎势,1 byte凛膏,從readIndex位置開始 | ||
readByte() | byte | 讀取數(shù)據(jù)到byte,1 byte脏榆,從readIndex位置開始 | ||
readInt() | int | 讀取integer值猖毫,讀4 byte轉(zhuǎn)換為integer,從readIndex位置開始 | ||
readBytes(byte[] bytes) | int | 讀取數(shù)據(jù)到bytes须喂,從readIndex位置開始 | ||
readBytes(ByteBuffer b) | 待存入數(shù)據(jù)對(duì)象 | int | 讀取數(shù)據(jù)到另一個(gè)ByteBuffer吁断,讀取數(shù)量 | |
writeByte(byte b) | 待寫入數(shù)據(jù) | ByteBuffer | 寫入Byte數(shù)據(jù),1 byte | |
write(int b) | 待寫入數(shù)據(jù) | ByteBuffer | 寫入int值的byte轉(zhuǎn)換結(jié)果坞生,即丟棄高位仔役,1 byte | |
writeInt(int b) | 待寫入int值 | ByteBuffer | 寫入integer數(shù)據(jù),4 byte | |
writeBytes(byte[] b) | 待寫入ByteArray | ByteBuffer | 寫入數(shù)組 | |
writeBytes(byte[] b, int dataLength) | 待寫入ByteArray | 指定寫入長度 | ByteBuffer | 寫入數(shù)組,并指定寫入長度 |
writeBytes(ByteBuffer b) | 待寫入ByteBuffer | ByteBuffer | 寫入一個(gè)ByteBuffer可讀數(shù)據(jù) | |
writeBytes(ByteBuffer b, int dataLength) | 待寫入ByteBuffer | 指定寫入長度 | ByteBuffer | 寫入一個(gè)ByteBuffer可讀數(shù)據(jù)的部分長度 |
五:原理解析
創(chuàng)建一個(gè)數(shù)組是己,通過讀寫index來表示當(dāng)前數(shù)組可操作區(qū)域又兵,不用多次創(chuàng)建新數(shù)組并拷貝了,雖然默認(rèn)數(shù)組可能會(huì)變得很大卒废,減少創(chuàng)建拷貝過程能提高性能沛厨,以空間換時(shí)間。另外數(shù)組一般不輕易超過4k吧摔认,都是碎片的小數(shù)據(jù)逆皮,用這種方案最合適,如果是大數(shù)據(jù)量参袱,那就沒有什么意義了电谣。
六:小期待
以下項(xiàng)目都是我圍繞遠(yuǎn)程控制寫的項(xiàng)目和子項(xiàng)目。都給star一遍吧蓖柔。??
項(xiàng)目(Github) | 語言 | 其他地址 | 運(yùn)行環(huán)境 | 項(xiàng)目說明 |
---|---|---|---|---|
RemoteDataControllerForWeb | JavaScript | 簡書 | 瀏覽器 | 遠(yuǎn)程數(shù)據(jù)調(diào)試控制臺(tái)Web端 |
RemoteDataControllerForAndroid | Java | 簡書 | Android設(shè)備 | 遠(yuǎn)程數(shù)據(jù)調(diào)試Android端 |
RemoteDataControllerForServer | Java | 簡書 | 運(yùn)行Java的設(shè)備 | 遠(yuǎn)程數(shù)據(jù)調(diào)試Server端 |
MiniHttpClient | Java | 簡書 | 運(yùn)行Java的設(shè)備 | 精簡的HttpClient |
MiniHttpServer | Java | 簡書 | 運(yùn)行Java的設(shè)備 | 支持部分Http協(xié)議的Server |
MiniTCPClient | Java | 簡書 | 運(yùn)行Java的設(shè)備 | TCP長連接庫辰企,支持粘包拆包處理 |
PackageMessage | Java | 簡書 | 運(yùn)行Java的設(shè)備 | TCP粘包與半包解決方案 |
ByteBuffer | Java | 簡書 | 運(yùn)行Java的設(shè)備 | 二進(jìn)制處理工具類 |
DataTables.AltEditor | JavaScript | 簡書 | 瀏覽器 | Web端表格編輯組件 |
我的小站:IT狗窩
技術(shù)聯(lián)系QQ:1264957104