pos機(jī)讓連接tcp是什么,java 中的 NIO 和 IO 到底是什么區(qū)別

 新聞資訊  |   2023-07-02 12:12  |  投稿人:pos機(jī)之家

網(wǎng)上有很多關(guān)于pos機(jī)讓連接tcp是什么,java 中的 NIO 和 IO 到底是什么區(qū)別的知識(shí),也有很多人為大家解答關(guān)于pos機(jī)讓連接tcp是什么的問(wèn)題,今天pos機(jī)之家(www.rcqwhg.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來(lái)看下吧!

本文目錄一覽:

1、pos機(jī)讓連接tcp是什么

pos機(jī)讓連接tcp是什么

此賬號(hào)為華為云開(kāi)發(fā)者社區(qū)官方運(yùn)營(yíng)賬號(hào),提供全面深入的云計(jì)算前景分析、豐富的技術(shù)干貨、程序樣例,分享華為云前沿資訊動(dòng)態(tài)

本文分享自華為云社區(qū)《java中的NIO和IO到底是什么區(qū)別?20個(gè)問(wèn)題告訴你答案【奔跑吧!JAVA】》,原文作者:breakDraw 。

NIO 即 New IO,這個(gè)庫(kù)是在 JDK1.4 中才引入的。NIO 和 IO 有相同的作用和目的,但實(shí)現(xiàn)方式不同,NIO 主要用到的是塊,所以 NIO 的效率要比 IO 高很多。

Q: NIO 和標(biāo)準(zhǔn) IO 有什么區(qū)別?

A:

標(biāo)準(zhǔn) IO, 基于字節(jié)流和字符流進(jìn)行操作,阻塞 IO。NIO 基于通道 channel 和緩沖區(qū) Buffer 進(jìn)行操作,支持非阻塞 IO,提供選擇器JavaNIO 核心 3 組件:Channels 通道

Q: 通道 Channel 對(duì)象能同時(shí)做讀寫(xiě)操作嗎?還是說(shuō)需要像標(biāo)準(zhǔn) IO 那樣,需要同時(shí)創(chuàng)建 input 和 output 對(duì)象才能做讀寫(xiě)操作?

A:通道 Channel 是雙向的, 既可以從 channel 中讀數(shù)據(jù),也可以寫(xiě)數(shù)據(jù)??梢钥吹郊饶苷{(diào)用 read 也能調(diào)用 write,且需要依賴(lài)緩沖區(qū) buffer。

FileChannel fileChannel = FileChannel.open(new File("a.txt").toPath()); ByteBuffer buf = ByteBuffer.allocate(1024); fileChannel.read(buf); fileChannel.write(buf);注意上圖上,fileChannel.read(buf)是將 a.txt 里的數(shù)據(jù)讀到 buf, 即 a.txt->buffileChannel.write(buf)是將 buf 里的數(shù)據(jù)寫(xiě)入到 a.txt 中, 即 buf->a.txt,不要搞反啦!通道和緩沖區(qū)的關(guān)系

Q: 通道支持異步讀寫(xiě)嗎

A:支持。

Q: 通道的讀寫(xiě)是否必須要依賴(lài)緩沖區(qū) buffer?

A: 一般都是依賴(lài) buffer 的。 但也支持 2 個(gè)管道之間的傳輸,即管道之間直接讀寫(xiě)。

String[] arr=new String[]{"a.txt","b.txt"};FileChannel in=new FileInputStream(arr[0]).getChannel();FileChannel out =new FileOutputStream(arr[1]).getChannel(); // 將a.txt中的數(shù)據(jù)直接寫(xiě)進(jìn)b.txt中,相當(dāng)于文件拷貝in.transferTo(0, in.size(), out);

常用的幾種 Channel

FileChannel

Java NIO 中的 FileChannel 是一個(gè)連接到文件的通道。可以通過(guò)文件通道讀寫(xiě)文件。FileChannel 無(wú)法設(shè)置為非阻塞模式,它總是運(yùn)行在阻塞模式下

創(chuàng)建方式

RandomAccessFile file = new RandomAccessFile("D:/aa.txt");FileChannel fileChannel = file.getChannel();SocketChannel

Java NIO 中的 SocketChannel 是一個(gè)連接到 TCP 網(wǎng)絡(luò)套接字的通道。

支持非阻塞模式 socketChannel.configureBlocking(false)。

可以通過(guò)以下 2 種方式創(chuàng)建 SocketChannel:

打開(kāi)一個(gè) SocketChannel 并連接到互聯(lián)網(wǎng)上的某臺(tái)服務(wù)器。

一個(gè)新連接到達(dá) ServerSocketChannel 時(shí),會(huì)創(chuàng)建一個(gè) SocketChannel

創(chuàng)建方式

SocketChannel socketChannel = SocketChannel.open();socketChannel.connect(new InetSocketAddress("192.168.1.100",80));ServerSocketChannel

Java NIO 中的 ServerSocketChannel 是一個(gè)可以監(jiān)聽(tīng)新進(jìn)來(lái)的 TCP 連接的通道, 就像標(biāo)準(zhǔn) IO 中的 ServerSocket 一樣。

ServerSocketChannel 類(lèi)在 java.nio.channels 包中。

SocketChannel 和 ServerSocketChannel 的區(qū)別: 前者用于客戶端,后者用于服務(wù)端

創(chuàng)建方式:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket.bind(new InetSocketAddress(80));serverSocketChannel.configureBlocking(false);while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); if(socketChannle != null) doSomething...}Buffer 緩沖區(qū)我們真正要把數(shù)據(jù)拿到或者要寫(xiě)數(shù)據(jù), 實(shí)際上都是通過(guò) buffer 進(jìn)行操作的。文件 <-> buffer<-> 數(shù)據(jù)buffer 是 1 個(gè)即可讀也可寫(xiě)的緩沖區(qū),擁有讀寫(xiě) 2 種模式。buffer 的 capacity 屬性限定了每個(gè) buffer 的最大容量,下面的 1024 就是 capacity。

ByteBuffer buf = ByteBuffer.allocate(1024);

buffer 擁有 1 個(gè) position 屬性,表示當(dāng)前的讀寫(xiě)位置。往 buffer 中寫(xiě)數(shù)據(jù)時(shí),position 就會(huì)增加。position 最大值為 capacity-1把 fileChannel 對(duì)應(yīng)文件里的數(shù)據(jù) 寫(xiě)入到 buffer,叫做寫(xiě)模式寫(xiě)之后,調(diào)用 flip,讓 buffer 的 postion 置 0,此時(shí)相當(dāng)于準(zhǔn)備讀取 buffer 里的數(shù)據(jù)(即調(diào)用 buffer.get()拿數(shù)據(jù))

(這個(gè)模式的叫法個(gè)人也覺(jué)得不太好,很容易繞,你可以就記憶成: flip 就是從寫(xiě)模式轉(zhuǎn)成讀模式?。?/p>

Q: buffer 調(diào)用 flip()方法從寫(xiě)模式切換到讀模式時(shí),position 會(huì)變成多少?

A: 變?yōu)?0。

ByteBuffer buf = ByteBuffer.allocate(1024); // 數(shù)據(jù)讀到buf中,并返回?cái)?shù)量,每次最多讀1024個(gè) int byteRead = fileChannel.read(buf); // 輸出byteRead的數(shù)量,最多為1024 System.out.println("position=" + buf.position()+", byteRead=" + byteRead); buf.flip(); // 切換到讀模式了,輸出0 System.out.println("position=" + buf.position());buffer 擁有 1 個(gè) limit 屬性。寫(xiě)模式下,buffer 的 limit 就是 buffer 的 capacity。

Q: 當(dāng) buffer 從寫(xiě)模式切換到讀模式時(shí),limit 為多少?

A: 每次切換前都要調(diào)用 flip(),切換后,limit 為寫(xiě)模式中的 position。

int byteRead = fileChannel.read(buf); // 輸出1024 System.out.println("limit=" + buf.limit() + ",postion=" + buf.position()); System.out.println("切換到讀模式"); buf.flip(); // 輸出byteRead數(shù)量 System.out.println("limit=" + buf.limit());

結(jié)果如下

Q: 向 buf 緩沖區(qū)寫(xiě)數(shù)據(jù)的方式有哪些?

A:

int byteRead = fileChannel.read(buf);

從通道中讀數(shù)據(jù)到 buf 中, 即相當(dāng)于向 buf 緩沖區(qū)中寫(xiě)數(shù)據(jù)。

buf.putChar(‘a(chǎn)’);

手動(dòng)向 buf 中寫(xiě)入字符 a, postion 加 1。

Q: 從 buf 緩沖區(qū)讀數(shù)據(jù)的方式有哪些?

int bytesWrite = fileChannel.write(buf)

buf 中的數(shù)據(jù)寫(xiě)入到管道,即相當(dāng)于 fileChannel 讀取 buf 中的數(shù)據(jù)。

byte getByte = buf.get()

手動(dòng)讀取 1 個(gè) buf 中的字符,postion 加 1.

Q: 手動(dòng)修改當(dāng)前緩沖區(qū)的 postion 的方法有哪些?

A:

rewind() 將 postion 設(shè)置為 0mark() 可以標(biāo)記 1 個(gè)特定的位置, 相當(dāng)于打標(biāo)記, 在一頓操作后,可通過(guò) reset()回到之前 mark()的位置(就像你需要 mark 我的這幾篇博文一樣!)

Q:1 個(gè) channel 管道支持多個(gè) buffer 嗎?

A: 支持。 通道的 write 和 read 方法都支持傳入 1 個(gè) buffer 數(shù)組,會(huì)按照順序做讀寫(xiě)操作。

Buffer 的種類(lèi):

Buffer 的另外 3 個(gè)方法:

warp:

根據(jù)一個(gè) byte[]來(lái)生成一個(gè)固定的 ByteBuffer 時(shí),使用 ByteBuffer.wrap()非法的合適。他會(huì)直接基于 byte[]數(shù)組生成一個(gè)新的 buffer,值也保持一致。

slice:

得到切片后的數(shù)組。

duplicate:

調(diào)用 duplicate 方法返回的 Buffer 對(duì)象就是復(fù)制了一份原始緩沖區(qū),復(fù)制了 position、limit、capacity 這些屬性

注意!

以上 warp\\slice\\duplicte 生成的緩沖區(qū) get 和 put 所操作的數(shù)組還是與原始緩沖區(qū)一樣的

所以對(duì)復(fù)制后的緩沖區(qū)進(jìn)行修改也會(huì)修改原始的緩沖區(qū),反之亦然

因此 duplicte、slice 一般是用于操作一下 poistion\\limit 等處理,但是原內(nèi)容不會(huì)去變他,否則就會(huì)引起 原緩沖器的修改。

Selector

selector 可用來(lái)在線程中關(guān)聯(lián)多個(gè)通道,并進(jìn)行事件監(jiān)聽(tīng)。

Q: 在 NIO 中 Selector 的好處是什么?

A:

可以用更少的線程來(lái)管理各個(gè)通道。減少線程上下文切換的資源開(kāi)銷(xiāo)。

Q: Selector 支持注冊(cè)哪種類(lèi)型的通道?

A:支持非阻塞的通道。通道要在注冊(cè)前調(diào)用 channel.configureBlocking(false) 設(shè)置為非阻塞。例如 FileChannel 就沒(méi)辦法注冊(cè),他注定是阻塞的。而 socketChannel 就可以支持非阻塞。

Q: Selector 注冊(cè)時(shí),支持監(jiān)聽(tīng)哪幾種事件,對(duì)應(yīng)的常量是什么?(啊最不喜歡記憶這種東西了…)

A:共有 4 種可監(jiān)聽(tīng)事件

Connect 成功連接到 1 個(gè)服務(wù)器,對(duì)應(yīng)常量 SelectionKey.OP_CONNECTAccept 準(zhǔn)備好接收新進(jìn)入的連接, 對(duì)應(yīng)常量 SelectionKey.OP_ACCEPTRead, 有數(shù)據(jù)可讀,對(duì)應(yīng)常量 SelectionKey.OP_READWrite 接收到往里寫(xiě)的數(shù)據(jù), 對(duì)應(yīng)常量 SelectionKey.OP_WRITE

如果希望對(duì)該通道監(jiān)聽(tīng)多種事件,可以用"|"位或操作符把常量連接起來(lái)。

int interestingSet = Selectionkey.OP_READ | Selectionkey.OP_WRITE;Selectionkey key = channel.register(selector,interestingSet)SelectionKey 鍵表示了一個(gè)特定的通道對(duì)象和一個(gè)特定的選擇器對(duì)象之間的注冊(cè)關(guān)系

Q: Selector 維護(hù)的 SelectionKey 集合共有哪幾種?

A:共有三種。

1. 已注冊(cè)的所有鍵的集合(Registered key set)

所有與選擇器關(guān)聯(lián)的通道所生成的鍵的集合稱(chēng)為已經(jīng)注冊(cè)的鍵的集合。并不是所有注冊(cè)過(guò)的鍵都仍然有效。這個(gè)集合通過(guò) keys()方法返回,并且可能是空的。這個(gè)已注冊(cè)的鍵的集合不是可以直接修改的;試圖這么做的話將引發(fā) java.lang.UnsupportedOperationException。

2. 已選擇的鍵的集合(Selected key set)

已注冊(cè)的鍵的集合的子集。這個(gè)集合的每個(gè)成員都是相關(guān)的通道被選擇器(在前一個(gè)選擇操作中)判斷為已經(jīng)準(zhǔn)備好的,并且包含于鍵的 interest 集合中的操作。這個(gè)集合通過(guò) selectedKeys()方法返回(并有可能是空的)。不要將已選擇的鍵的集合與 ready 集合弄混了。這是一個(gè)鍵的集合,每個(gè)鍵都關(guān)聯(lián)一個(gè)已經(jīng)準(zhǔn)備好至少一種操作的通道。每個(gè)鍵都有一個(gè)內(nèi)嵌的 ready 集合,指示了所關(guān)聯(lián)的通道已經(jīng)準(zhǔn)備好的操作。鍵可以直接從這個(gè)集合中移除,但不能添加。試圖向已選擇的鍵的集合中添加元素將拋出 java.lang.UnsupportedOperationException。

3. 已取消的鍵的集合(Cancelled key set)

已注冊(cè)的鍵的集合的子集,這個(gè)集合包含了 cancel()方法被調(diào)用過(guò)的鍵(這個(gè)鍵已經(jīng)被無(wú)效化),但它們還沒(méi)有被注銷(xiāo)。這個(gè)集合是選擇器對(duì)象的私有成員,因而無(wú)法直接訪問(wèn)。

注冊(cè)之后, 如何使用 selector 對(duì)準(zhǔn)備就緒的通道做處理:

1. 調(diào)用 select()方法獲取已就緒的通道,返回的 int 值表示有多少通道已經(jīng)就緒

2. 從 selector 中獲取 selectedkeys

3. 遍歷 selectedkeys

4. 查看各 SelectionKey 中 是否有事件就緒了。

5. 如果有事件就緒,從 key 中獲取對(duì)應(yīng)對(duì)應(yīng)管道。做對(duì)應(yīng)處理

類(lèi)似如下,一般都會(huì)啟 1 個(gè)線程來(lái) run 這個(gè) selector 監(jiān)聽(tīng)的處理:

while(true) { int readyNum = selector.select(); if (readyNum == 0) { continue; } Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectedKeys.iterator(); while(it.hasNext()) { SelectionKey key = it.next(); if(key.isAcceptable()) { // 接受連接 } else if (key.isReadable()) { // 通道可讀 } else if (key.isWritable()) { // 通道可寫(xiě) } it.remove(); }}

Q:select()方法其實(shí)是阻塞方法,即調(diào)用時(shí)會(huì)進(jìn)入等待,直到把所有通道都輪詢(xún)完畢。如果希望提前結(jié)束 select(),有哪些方法?

A:有 2 個(gè)辦法:

wakeup(), 調(diào)用后,select()方法立刻返回。

close(), 直接關(guān)閉 selector。

PS: 之前說(shuō) NIO 是非阻塞 IO,但為什么上面卻說(shuō) select()方法是阻塞的?

其實(shí) NIO 的非阻塞,指的是 IO 不阻塞,即我們不會(huì)卡在 read()處,我們會(huì)用 selector 去查詢(xún)就緒狀態(tài),如果狀態(tài) ok 就。而查詢(xún)操作是需要時(shí)間,因此 select()必須要把所有通道都檢查一遍才能告訴結(jié)果,因此 select 這個(gè)查詢(xún)操作是阻塞的。其他

Q: 多線程讀寫(xiě)同一文件時(shí),如何加鎖保證線程安全?

A:使用 FileChannel 的加鎖功能。

RandomAccessFile randFile = new RandomAccessFile(target, "rw");FileChannel channel = randFile.getChannel();// pos和siz決定加鎖區(qū)域, shared指定是否是共享鎖FileLock fileLock = channel.lock(pos , size , shared);if (fileLock!=null) {do(); // 這里簡(jiǎn)化了,實(shí)際上應(yīng)該用try-catchfileLock.release();}

Q: 如果需要讀 1 個(gè)特大文件,可以使用什么緩沖區(qū)?

A:使用 MappedByteBuffer。這個(gè)緩沖區(qū)可以把大文件理解成 1 個(gè) byte 數(shù)組來(lái)訪問(wèn)(但實(shí)際上并沒(méi)有加載這么大的 byte 數(shù)組,實(shí)際內(nèi)容放在內(nèi)存+虛存中)。主要通過(guò) FileChannel.map(模式,起始位置,區(qū)域)來(lái)生成 1 個(gè) MappedByteBuffer。然后可以用 put 和 get 去處理對(duì)應(yīng)位置的 byte。

int length = 0x8FFFFFF;//一個(gè)byte占1B,所以共向文件中存128M的數(shù)據(jù)try (FileChannel channel = FileChannel.open(Paths.get("src/c.txt"),StandardOpenOption.READ, StandardOpenOption.WRITE);) {MappedByteBuffer mapBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, length);for(int i=0;i<length;i++) {mapBuffer.put((byte)0);}for(int i = length/2;i<length/2+4;i++) {//像數(shù)組一樣訪問(wèn)System.out.println(mapBuffer.get(i));}}

三種模式:

MapMode.READ_ONLY(只讀): 試圖修改得到的緩沖區(qū)將導(dǎo)致拋出 ReadOnlyBufferException。MapMode.READ_WRITE(讀/寫(xiě)): 對(duì)得到的緩沖區(qū)的更改會(huì)寫(xiě)入文件,需要調(diào)用 fore()方法MapMode.PRIVATE(專(zhuān)用): 可讀可寫(xiě),但是修改的內(nèi)容不會(huì)寫(xiě)入文件,只是 buffer 自身的改變。

Q:NIO 中 ByteBuffer, 該如何根據(jù)正確的編碼,轉(zhuǎn)為對(duì)應(yīng)的 CharBuffer

A:利用 Charset 的 decode 功能。

ByteBuffer byteBuffer = ...;Charset charset = Charset.forName("UTF-8");CharBuffer charBuffer = charset.decode(byteBuffer);

如果是 CharBuffer 轉(zhuǎn) ByteBuffer, 就用 charset.encode。

點(diǎn)擊關(guān)注,第一時(shí)間了解華為云新鮮技術(shù)~

以上就是關(guān)于pos機(jī)讓連接tcp是什么,java 中的 NIO 和 IO 到底是什么區(qū)別的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于pos機(jī)讓連接tcp是什么的知識(shí),希望能夠幫助到大家!

轉(zhuǎn)發(fā)請(qǐng)帶上網(wǎng)址:http://www.rcqwhg.com/news/76744.html

你可能會(huì)喜歡:

版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 babsan@163.com 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。