網(wǎng)上有很多關(guān)于pos機(jī)解碼教程,ByteBuffer的基本使用的知識(shí),也有很多人為大家解答關(guān)于pos機(jī)解碼教程的問(wèn)題,今天pos機(jī)之家(m.tjfsxbj.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來(lái)看下吧!
本文目錄一覽:
pos機(jī)解碼教程
一 、byteBuffer的基本使用
ByteBuffer 正確的使用姿勢(shì):
1 創(chuàng)建ByteBuffer對(duì)象: ByteBuffer buffer = ByteBuffer.allocate(10); 一般通過(guò)這個(gè)allocate()方法來(lái)分配
2 向buffer寫(xiě)入數(shù)據(jù),調(diào)用channel.read(buffer)方法
3 調(diào)用flip()方法,切換到讀取模式
4 從buffer中讀取數(shù)據(jù),buffer.get()
5 調(diào)用clear()或者compact()方法切換到寫(xiě)模式
6 重復(fù)2-5步
實(shí)例 :
用FileChannel讀取test.txt文件到ByteBuffer,然后輸出,test.txt內(nèi)容為: 12345678fdsfds
/** * @program: isc-study * @description: * @author: wangjinwei * @create: 2021-09-26 09:17 **/public class ByteBufferTest { public static void main(String[] args) { //用FileChannel 來(lái)讀取文件 try (RandomAccessFile file = new RandomAccessFile("E:\\\est.txt", "rw")) { FileChannel channel = file.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(10); while (true) { int len = channel.read(buffer); //讀完了 if (len == -1) { break; } //切換到讀取模式 buffer.flip(); while (buffer.hasRemaining()) { System.out.println((char) buffer.get()); } //清空到寫(xiě)模式 buffer.clear(); } } catch (IOException e) { e.printStackTrace(); } }}
擴(kuò)展總結(jié):
1 這里有個(gè)問(wèn)題 NIO的優(yōu)勢(shì)在非阻塞,那么這里 FileChannel可以設(shè)置為非阻塞模式么?
答案:當(dāng)然不可以,F(xiàn)ileChannel這個(gè)類繼承了AbstractInterruptibleChannel抽象類,并沒(méi)有繼承SelectableChannel設(shè)置為阻塞模式的方法在SelectableChannel類里。
2 ByteBuffer.allocate(10)返回的是HeapByteBuffer 也就是說(shuō)是堆內(nèi)存,堆內(nèi)存讀寫(xiě)效率較低,存入的對(duì)象是受jvm GC管理
ByteBuffer.allocateDirect(10)返回直接內(nèi)存,直接內(nèi)存效率高,存的對(duì)象不受gc管理,當(dāng)buffer對(duì)象被回收時(shí),會(huì)執(zhí)行釋放的方法
二、ByteBuffer的分散聚集
分散(scatter)從Channel中讀取是指在讀操作時(shí)將讀取的數(shù)據(jù)寫(xiě)入多個(gè)buffer中。因此,Channel將從Channel中讀取的數(shù)據(jù)“分散(scatter)”到多個(gè)Buffer中。
還是以test.txt為例,讀取時(shí)候使用多個(gè)buffer
public static void bufferTest2() { try (RandomAccessFile file = new RandomAccessFile("E:\\\est.txt", "rw")) { FileChannel channel = file.getChannel(); ByteBuffer buf1 = ByteBuffer.allocate(2); ByteBuffer buf2 = ByteBuffer.allocate(2); ByteBuffer[] bufs = {buf1, buf2}; while (true) { //分散讀取 long len = channel.read(bufs); //讀完了 if (len == -1) { break; } for (ByteBuffer buffer : bufs) { buffer.flip(); while (buffer.hasRemaining()) { System.out.println((char) buffer.get()); } //清空到寫(xiě)模式 buffer.clear(); } } } catch (IOException e) { e.printStackTrace(); }}
聚集(gather)寫(xiě)入Channel是指在寫(xiě)操作時(shí)將多個(gè)buffer的數(shù)據(jù)寫(xiě)入同一個(gè)Channel,因此,Channel 將多個(gè)Buffer中的數(shù)據(jù)“聚集(gather)”后發(fā)送到Channel。
public static void bufferTest3() { try (RandomAccessFile file = new RandomAccessFile("E:\\\est.txt", "rw"); RandomAccessFile file2 = new RandomAccessFile("E:\\\est2.txt", "rw")) { FileChannel channel = file.getChannel(); FileChannel channel2 = file2.getChannel(); ByteBuffer buf1 = ByteBuffer.allocate(2); ByteBuffer buf2 = ByteBuffer.allocate(2); ByteBuffer[] bufs = {buf1, buf2}; while (true) { //分散讀取 long len = channel.read(bufs); //讀完了 if (len == -1) { break; } for (ByteBuffer buffer : bufs) { buffer.flip(); } //聚集寫(xiě)入 channel2.write(bufs); for (ByteBuffer buffer : bufs) { buffer.clear(); } } } catch (IOException e) { e.printStackTrace(); }}
總結(jié):scatter / gather經(jīng)常用于需要將傳輸?shù)臄?shù)據(jù)分開(kāi)處理的場(chǎng)合,例如傳輸一個(gè)由消息頭和消息體組成的消息,
你可能會(huì)將消息體和消息頭分散到不同的buffer中,這樣你可以方便的處理消息頭和消息體。這個(gè)分散/聚集讀取,主要
學(xué)習(xí)的這個(gè)思想,本身用途不是很大
三、ByteBuffer 的拆包粘包
TCP傳輸數(shù)據(jù)時(shí)候 將多個(gè)發(fā)往接收端的包,為了更有效的發(fā)到對(duì)方,使用了優(yōu)化方法(Nagle算法),將多次間隔較小且數(shù)據(jù)量小的數(shù)據(jù),
合并成一個(gè)大的數(shù)據(jù)塊,然后進(jìn)行封包。這樣,接收端,就難于分辨出來(lái)了。
比如要發(fā)送下面3行字符
Hello,world\I'm zhangsan\How are you?\
變成了下面的兩個(gè) byteBuffer (粘包,半包)
Hello,world\I'm zhangsan\How are you?\
發(fā)生拆包粘包的場(chǎng)景:
1. 應(yīng)用程序?qū)懭氲臄?shù)據(jù)大于套接字緩沖區(qū)大小,這將會(huì)發(fā)生拆包。
2.應(yīng)用程序?qū)懭霐?shù)據(jù)小于套接字緩沖區(qū)大小,網(wǎng)卡將應(yīng)用多次寫(xiě)入的數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)上,這將會(huì)發(fā)生粘包。
3.進(jìn)行MSS(最大報(bào)文長(zhǎng)度)大小的TCP分段,當(dāng)TCP報(bào)文長(zhǎng)度-TCP頭部長(zhǎng)度>MSS的時(shí)候?qū)l(fā)生拆包。
4.接收方法不及時(shí)讀取套接字緩沖區(qū)數(shù)據(jù),這將發(fā)生粘包。
所以發(fā)送端,接收端在接受數(shù)據(jù)時(shí)要做一些特殊處理 比如 數(shù)據(jù)之間使用 其他特殊符號(hào)進(jìn)行分隔,本例中使用\
public static void bufferTest4() { ByteBuffer source = ByteBuffer.allocate(32); // 11 24 source.put("Hello,world\I'm zhangsan\Ho".getBytes()); split(source); source.put("w are you?\haha!\".getBytes()); split(source);} public static void split(ByteBuffer source) { source.flip(); int oldLimit = source.limit(); for (int i = 0; i < oldLimit; i++) { if (source.get(i) == '\') { System.out.println(i); ByteBuffer target = ByteBuffer.allocate(i + 1 - source.position()); // 0 ~ limit source.limit(i + 1); //這里會(huì)修改source的pos值 只會(huì)讀取limit-position長(zhǎng)度的字節(jié) target.put(source); //打印buffer printBuffer(target); //為了給target賦值,上面修改了source的limit 這里把源buffer的limit設(shè)置回去, source.limit(oldLimit); } } source.compact();} public static void printBuffer(ByteBuffer buffer) { buffer.flip(); System.out.println(new String(buffer.array(),0,buffer.limit())); //清空到寫(xiě)模式 buffer.clear();} public static void main(String[] args) { bufferTest4();}
總結(jié):這里只需要了解就可以了,netty提供了強(qiáng)大的編解碼工具
以上就是關(guān)于pos機(jī)解碼教程,ByteBuffer的基本使用的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于pos機(jī)解碼教程的知識(shí),希望能夠幫助到大家!
