一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術(shù)|

服務(wù)器之家 - 編程語言 - JAVA教程 - 詳解java NIO之Channel(通道)

詳解java NIO之Channel(通道)

2020-07-02 12:05rickiyang JAVA教程

這篇文章主要介紹了詳解java NIO之Channel(通道)的相關(guān)資料,文中講解非常詳細(xì),示例代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

通道Channel)是java.nio的第二個(gè)主要?jiǎng)?chuàng)新。它們既不是一個(gè)擴(kuò)展也不是一項(xiàng)增強(qiáng),而是全新、極好的Java I/O示例,提供與I/O服務(wù)的直接連接。Channel用于在字節(jié)緩沖區(qū)和位于通道另一側(cè)的實(shí)體(通常是一個(gè)文件或套接字)之間有效地傳輸數(shù)據(jù)。

channel介紹

通道是訪問I/O服務(wù)的導(dǎo)管。I/O可以分為廣義的兩大類別:File I/O和Stream I/O。那么相應(yīng)地有兩種類型的通道也就不足為怪了,它們是文件(file)通道和套接字(socket)通道。我們看到在api里有一個(gè)FileChannel類和三個(gè)socket通道類:SocketChannel、ServerSocketChannel和DatagramChannel。

通道可以以多種方式創(chuàng)建。Socket通道有可以直接創(chuàng)建新socket通道的工廠方法。但是一個(gè)FileChannel對象卻只能通過在一個(gè)打開的RandomAccessFile、FileInputStream或FileOutputStream對象上調(diào)用getChannel( )方法來獲取。你不能直接創(chuàng)建一個(gè)FileChannel對象。

我們先來看一下FileChannel的用法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 創(chuàng)建文件輸出字節(jié)流
FileOutputStream fos = new FileOutputStream("data.txt");
//得到文件通道
FileChannel fc = fos.getChannel();
//往通道寫入ByteBuffer
fc.write(ByteBuffer.wrap("Some text ".getBytes()));
//關(guān)閉流
fos.close();
 
//隨機(jī)訪問文件
RandomAccessFile raf = new RandomAccessFile("data.txt", "rw");
//得到文件通道
fc = raf.getChannel();
//設(shè)置通道的文件位置 為末尾
fc.position(fc.size());
//往通道寫入ByteBuffer
fc.write(ByteBuffer.wrap("Some more".getBytes()));
//關(guān)閉
raf.close();
 
//創(chuàng)建文件輸入流
FileInputStream fs = new FileInputStream("data.txt");
//得到文件通道
fc = fs.getChannel();
//分配ByteBuffer空間大小
ByteBuffer buff = ByteBuffer.allocate(BSIZE);
//從通道中讀取ByteBuffer
fc.read(buff);
//調(diào)用此方法為一系列通道寫入或相對獲取 操作做好準(zhǔn)備
buff.flip();
//從ByteBuffer從依次讀取字節(jié)并打印
while (buff.hasRemaining()){
 System.out.print((char) buff.get());
}
fs.close();

再來看一下SocketChannel:

?
1
2
3
4
5
SocketChannel sc = SocketChannel.open( );
sc.connect (new InetSocketAddress ("somehost", someport));
ServerSocketChannel ssc = ServerSocketChannel.open( );
ssc.socket( ).bind (new InetSocketAddress (somelocalport));
DatagramChannel dc = DatagramChannel.open( );

可以設(shè)置 SocketChannel 為非阻塞模式(non-blocking mode).設(shè)置之后,就可以在異步模式下調(diào)用connect(), read() 和write()了。如果SocketChannel在非阻塞模式下,此時(shí)調(diào)用connect(),該方法可能在連接建立之前就返回了。為了確定連接是否建立,可以調(diào)用finishConnect()的方法。像這樣:

?
1
2
3
4
5
6
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
 
while(! socketChannel.finishConnect() ){
 //wait, or do something else...
}

服務(wù)器端的使用經(jīng)常會(huì)考慮到非阻塞socket通道,因?yàn)樗鼈兪雇瑫r(shí)管理很多socket通道變得更容易。但是,在客戶端使用一個(gè)或幾個(gè)非阻塞模式的socket通道也是有益處的,例如,借助非阻塞socket通道,GUI程序可以專注于用戶請求并且同時(shí)維護(hù)與一個(gè)或多個(gè)服務(wù)器的會(huì)話。在很多程序上,非阻塞模式都是有用的。

調(diào)用finishConnect( )方法來完成連接過程,該方法任何時(shí)候都可以安全地進(jìn)行調(diào)用。假如在一個(gè)非阻塞模式的SocketChannel對象上調(diào)用finishConnect( )方法,將可能出現(xiàn)下列情形之一:

  • connect( )方法尚未被調(diào)用。那么將產(chǎn)生NoConnectionPendingException異常。
  • 連接建立過程正在進(jìn)行,尚未完成。那么什么都不會(huì)發(fā)生,finishConnect( )方法會(huì)立即返回false值。
  • 在非阻塞模式下調(diào)用connect( )方法之后,SocketChannel又被切換回了阻塞模式。那么如果有必要的話,調(diào)用線程會(huì)阻塞直到連接建立完成,finishConnect( )方法接著就會(huì)返回true值。在初次調(diào)用connect( )或最后一次調(diào)用finishConnect( )之后,連接建立過程已經(jīng)完成。那么SocketChannel對象的內(nèi)部狀態(tài)將被更新到已連接狀態(tài),finishConnect( )方法會(huì)返回true值,然后SocketChannel對象就可以被用來傳輸數(shù)據(jù)了。
  • 連接已經(jīng)建立。那么什么都不會(huì)發(fā)生,finishConnect( )方法會(huì)返回true值。

Socket通道是線程安全的。并發(fā)訪問時(shí)無需特別措施來保護(hù)發(fā)起訪問的多個(gè)線程,不過任何時(shí)候都只有一個(gè)讀操作和一個(gè)寫操作在進(jìn)行中。請記住,sockets是面向流的而非包導(dǎo)向的。它們可以保證發(fā)送的字節(jié)會(huì)按照順序到達(dá)但無法承諾維持字節(jié)分組。某個(gè)發(fā)送器可能給一個(gè)socket寫入了20個(gè)字節(jié)而接收器調(diào)用read( )方法時(shí)卻只收到了其中的3個(gè)字節(jié)。剩下的17個(gè)字節(jié)還是傳輸中。由于這個(gè)原因,讓多個(gè)不配合的線程共享某個(gè)流socket的同一側(cè)絕非一個(gè)好的設(shè)計(jì)選擇。

最后再看一下DatagramChannel:

最后一個(gè)socket通道是DatagramChannel。正如SocketChannel對應(yīng)Socket,ServerSocketChannel對應(yīng)ServerSocket,每一個(gè)DatagramChannel對象也有一個(gè)關(guān)聯(lián)的DatagramSocket對象。不過原命名模式在此并未適用:“DatagramSocketChannel”顯得有點(diǎn)笨拙,因此采用了簡潔的“DatagramChannel”名稱。

正如SocketChannel模擬連接導(dǎo)向的流協(xié)議(如TCP/IP),DatagramChannel則模擬包導(dǎo)向的無連接協(xié)議(如UDP/IP):

創(chuàng)建DatagramChannel的模式和創(chuàng)建其他socket通道是一樣的:調(diào)用靜態(tài)的open( )方法來創(chuàng)建一個(gè)新實(shí)例。新DatagramChannel會(huì)有一個(gè)可以通過調(diào)用socket( )方法獲取的對等DatagramSocket對象。DatagramChannel對象既可以充當(dāng)服務(wù)器(監(jiān)聽者)也可以充當(dāng)客戶端(發(fā)送者)。如果你希望新創(chuàng)建的通道負(fù)責(zé)監(jiān)聽,那么通道必須首先被綁定到一個(gè)端口或地址/端口組合上。綁定DatagramChannel同綁定一個(gè)常規(guī)的DatagramSocket沒什么區(qū)別,都是委托對等socket對象上的API實(shí)現(xiàn)的:

?
1
2
3
DatagramChannel channel = DatagramChannel.open( );
DatagramSocket socket = channel.socket( );
socket.bind (new InetSocketAddress (portNumber));

DatagramChannel是無連接的。每個(gè)數(shù)據(jù)報(bào)(datagram)都是一個(gè)自包含的實(shí)體,擁有它自己的目的地址及不依賴其他數(shù)據(jù)報(bào)的數(shù)據(jù)凈荷。與面向流的的socket不同,DatagramChannel可以發(fā)送單獨(dú)的數(shù)據(jù)報(bào)給不同的目的地址。同樣,DatagramChannel對象也可以接收來自任意地址的數(shù)據(jù)包。每個(gè)到達(dá)的數(shù)據(jù)報(bào)都含有關(guān)于它來自何處的信息(源地址)。

一個(gè)未綁定的DatagramChannel仍能接收數(shù)據(jù)包。當(dāng)一個(gè)底層socket被創(chuàng)建時(shí),一個(gè)動(dòng)態(tài)生成的端口號(hào)就會(huì)分配給它。綁定行為要求通道關(guān)聯(lián)的端口被設(shè)置為一個(gè)特定的值(此過程可能涉及安全檢查或其他驗(yàn)證)。不論通道是否綁定,所有發(fā)送的包都含有DatagramChannel的源地址(帶端口號(hào))。未綁定的DatagramChannel可以接收發(fā)送給它的端口的包,通常是來回應(yīng)該通道之前發(fā)出的一個(gè)包。已綁定的通道接收發(fā)送給它們所綁定的熟知端口(wellknown port)的包。數(shù)據(jù)的實(shí)際發(fā)送或接收是通過send( )和receive( )方法來實(shí)現(xiàn)的。

注意:假如您提供的ByteBuffer沒有足夠的剩余空間來存放您正在接收的數(shù)據(jù)包,沒有被填充的字節(jié)都會(huì)被悄悄地丟棄。

Scatter/Gather

通道提供了一種被稱為Scatter/Gather的重要新功能(有時(shí)也被稱為矢量I/O)。它是指在多個(gè)緩沖區(qū)上實(shí)現(xiàn)一個(gè)簡單的I/O操作。對于一個(gè)write操作而言,數(shù)據(jù)是從幾個(gè)緩沖區(qū)按順序抽取(稱為gather)并沿著通道發(fā)送的。緩沖區(qū)本身并不需要具備這種gather的能力(通常它們也沒有此能力)。該gather過程的效果就好比全部緩沖區(qū)的內(nèi)容被連結(jié)起來,并在發(fā)送數(shù)據(jù)前存放到一個(gè)大的緩沖區(qū)中。對于read操作而言,從通道讀取的數(shù)據(jù)會(huì)按順序被散布(稱為scatter)到多個(gè)緩沖區(qū),將每個(gè)緩沖區(qū)填滿直至通道中的數(shù)據(jù)或者緩沖區(qū)的最大空間被消耗完。

scatter / gather經(jīng)常用于需要將傳輸?shù)臄?shù)據(jù)分開處理的場合,例如傳輸一個(gè)由消息頭和消息體組成的消息,你可能會(huì)將消息體和消息頭分散到不同的buffer中,這樣你可以方便的處理消息頭和消息體。

Scattering Reads是指數(shù)據(jù)從一個(gè)channel讀取到多個(gè)buffer中。如下圖描述:

詳解java NIO之Channel(通道)

代碼示例如下:

?
1
2
3
4
ByteBuffer header = ByteBuffer.allocateDirect (10);
ByteBuffer body = ByteBuffer.allocateDirect (80);
ByteBuffer [] buffers = { header, body };
int bytesRead = channel.read (buffers);

Gathering Writes是指數(shù)據(jù)從多個(gè)buffer寫入到同一個(gè)channel。如下圖描述:

詳解java NIO之Channel(通道)

代碼示例如下:

?
1
2
3
4
ByteBuffer header = ByteBuffer.allocateDirect (10);
ByteBuffer body = ByteBuffer.allocateDirect (80);
ByteBuffer [] buffers = { header, body };
channel.write(bufferArray);

使用得當(dāng)?shù)脑挘琒catter/Gather會(huì)是一個(gè)極其強(qiáng)大的工具。它允許你委托操作系統(tǒng)來完成辛苦活:將讀取到的數(shù)據(jù)分開存放到多個(gè)存儲(chǔ)桶(bucket)或者將不同的數(shù)據(jù)區(qū)塊合并成一個(gè)整體。這是一個(gè)巨大的成就,因?yàn)椴僮飨到y(tǒng)已經(jīng)被高度優(yōu)化來完成此類工作了。它節(jié)省了您來回移動(dòng)數(shù)據(jù)的工作,也就避免了緩沖區(qū)拷貝和減少了您需要編寫、調(diào)試的代碼數(shù)量。既然您基本上通過提供數(shù)據(jù)容器引用來組合數(shù)據(jù),那么按照不同的組合構(gòu)建多個(gè)緩沖區(qū)陣列引用,各種數(shù)據(jù)區(qū)塊就可以以不同的方式來組合了。下面的例子好地詮釋了這一點(diǎn):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class GatheringTest {
 private static final String DEMOGRAPHIC = "output.txt";
 public static void main (String [] argv) throws Exception {
  int reps = 10;
  if (argv.length > 0) {
   reps = Integer.parseInt(argv[0]);
  }
  FileOutputStream fos = new FileOutputStream(DEMOGRAPHIC);
  GatheringByteChannel gatherChannel = fos.getChannel();
 
  ByteBuffer[] bs = utterBS(reps);
 
  while (gatherChannel.write(bs) > 0) {
   // 不做操作,讓通道把數(shù)據(jù)輸出到文件寫完
  }
  System.out.println("Mindshare paradigms synergized to " + DEMOGRAPHIC);
  fos.close();
 }
 private static String [] col1 = { "Aggregate", "Enable", "Leverage",
          "Facilitate", "Synergize", "Repurpose",
          "Strategize", "Reinvent", "Harness"
         };
 
 private static String [] col2 = { "cross-platform", "best-of-breed", "frictionless",
          "ubiquitous", "extensible", "compelling",
          "mission-critical", "collaborative", "integrated"
         };
 
 private static String [] col3 = { "methodologies", "infomediaries", "platforms", "schemas", "mindshare", "paradigms", "functionalities", "web services", "infrastructures" };
 
 private static String newline = System.getProperty ("line.separator");
 
 
 private static ByteBuffer [] utterBS (int howMany) throws Exception {
  List list = new LinkedList();
  for (int i = 0; i < howMany; i++) {
   list.add(pickRandom(col1, " "));
   list.add(pickRandom(col2, " "));
   list.add(pickRandom(col3, newline));
  }
  ByteBuffer[] bufs = new ByteBuffer[list.size()];
  list.toArray(bufs);
  return (bufs);
 }
 private static Random rand = new Random( );
 
 
 /**
  * 隨機(jī)生成字符
  * @param strings
  * @param suffix
  * @return
  * @throws Exception
  */
 private static ByteBuffer pickRandom (String [] strings, String suffix) throws Exception {
  String string = strings [rand.nextInt (strings.length)];
  int total = string.length() + suffix.length( );
  ByteBuffer buf = ByteBuffer.allocate (total);
  buf.put (string.getBytes ("US-ASCII"));
  buf.put (suffix.getBytes ("US-ASCII"));
  buf.flip( );
  return (buf);
 }
}

輸出為:

 Reinvent integrated web services
 Aggregate best-of-breed platforms
 Harness frictionless platforms
 Repurpose extensible paradigms
 Facilitate ubiquitous methodologies
 Repurpose integrated methodologies
 Facilitate mission-critical paradigms
 Synergize compelling methodologies
 Reinvent compelling functionalities
 Facilitate extensible platforms

雖然這種輸出沒有什么意義,但是gather確是很容易的讓我們把它輸出出來。

Pipe

java.nio.channels包中含有一個(gè)名為Pipe(管道)的類。廣義上講,管道就是一個(gè)用來在兩個(gè)實(shí)體之間單向傳輸數(shù)據(jù)的導(dǎo)管。
Java NIO 管道是2個(gè)線程之間的單向數(shù)據(jù)連接。Pipe有一個(gè)source通道和一個(gè)sink通道。數(shù)據(jù)會(huì)被寫到sink通道,從source通道讀取。Pipe類創(chuàng)建一對提供環(huán)回機(jī)制的Channel對象。這兩個(gè)通道的遠(yuǎn)端是連接起來的,以便任何寫在SinkChannel對象上的數(shù)據(jù)都能出現(xiàn)在SourceChannel對象上。

下面我們來創(chuàng)建一條Pipe,并向Pipe中寫數(shù)據(jù):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//通過Pipe.open()方法打開管道
Pipe pipe = Pipe.open();
 
//要向管道寫數(shù)據(jù),需要訪問sink通道
Pipe.SinkChannel sinkChannel = pipe.sink();
 
//通過調(diào)用SinkChannel的write()方法,將數(shù)據(jù)寫入SinkChannel
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
 sinkChannel.write(buf);
}

再看如何從管道中讀取數(shù)據(jù):

讀取管道的數(shù)據(jù),需要訪問source通道:

?
1
Pipe.SourceChannel sourceChannel = pipe.source();

調(diào)用source通道的read()方法來讀取數(shù)據(jù):

?
1
2
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = sourceChannel.read(buf);

read()方法返回的int值會(huì)告訴我們多少字節(jié)被讀進(jìn)了緩沖區(qū)。

到此我們就把通道的簡單用法講完了,要想會(huì)用還是得多去練習(xí),多模擬使用,這樣才知道什么時(shí)候用以及怎么用,下節(jié)我們來講選擇器-Selectors。

以上就是詳解java NIO之Channel(通道)的詳細(xì)內(nèi)容,更多關(guān)于JAVA NIO channel(通道)的資料請關(guān)注服務(wù)器之家其它相關(guān)文章!

原文鏈接:https://www.cnblogs.com/rickiyang/p/11074241.html

延伸 · 閱讀

精彩推薦
  • JAVA教程java和jsp中的request使用示例

    java和jsp中的request使用示例

    這篇文章主要介紹了java和jsp中的request使用示例,需要的朋友可以參考下 ...

    java技術(shù)網(wǎng)2152019-11-07
  • JAVA教程Java基于Tcp協(xié)議的socket編程實(shí)例

    Java基于Tcp協(xié)議的socket編程實(shí)例

    這篇文章主要介紹了Java基于Tcp協(xié)議的socket編程實(shí)例,較為詳細(xì)的分析了socket編程客戶端與服務(wù)器端的具體實(shí)現(xiàn)步驟與使用技巧,具有一定的參考借鑒價(jià)值,需要...

    shichen20142972019-12-07
  • JAVA教程java多線程詳細(xì)總結(jié)

    java多線程詳細(xì)總結(jié)

    以下小編就對java中的多線程進(jìn)行了詳細(xì)的總結(jié)分析,需要的朋友可以過來參考下,希望對大家有所幫助 ...

    java之家4322019-10-16
  • JAVA教程Mybatis generator的使用全面解析

    Mybatis generator的使用全面解析

    這篇文章主要介紹了Mybatis generator的使用,非常不錯(cuò),具有參考借鑒價(jià)值,對mybatis generator的使用相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧...

    woshixuye4972020-06-12
  • JAVA教程Java8中的default方法詳解

    Java8中的default方法詳解

    這篇文章主要介紹了Java8中的default方法詳解,Java 8新增了default方法,它可以在接口添加新功能特性,而且還不影響接口的實(shí)現(xiàn)類,需要的朋友可以參考下 ...

    junjie4542019-12-10
  • JAVA教程java 抽象類與接口的區(qū)別介紹

    java 抽象類與接口的區(qū)別介紹

    這篇文章主要介紹了java 抽象類與接口的區(qū)別介紹的相關(guān)資料,需要的朋友可以參考下 ...

    java教程網(wǎng)3152020-06-23
  • JAVA教程使用jdk7的nio2操作文件拷貝和剪切示例

    使用jdk7的nio2操作文件拷貝和剪切示例

    使用jdk7的NIO2進(jìn)行文件或文件夾的拷貝移動(dòng)操作。可以自動(dòng)創(chuàng)建路徑,差異化更新文件,簡單的出錯(cuò)重連機(jī)制 ...

    java教程網(wǎng)5112019-11-05
  • JAVA教程使用Javacsv.jar的jar包操作csv文件的方法

    使用Javacsv.jar的jar包操作csv文件的方法

    使用javacsv的jar包很方便的可以操作csv文件。下面通過本教程給大家介紹使用javacsv.jar操作csv文件的方法,感興趣的朋友一起看下吧 ...

    爪哇小漢4032020-06-05
主站蜘蛛池模板: 欧美视频网址 | 我与白丝同桌的故事h文 | 国产日韩一区二区 | 日韩视频免费观看 | 五月天色网站 | 欧美日韩一区二区三区久久 | 视频网站入口在线看 | 日韩欧美色图 | 亚洲高清在线天堂精品 | 四虎影院精品 | 好涨好爽乱岳 | 国产精品1页 | 亚洲国产在线2o20 | 成人在线免费观看 | 日本老妇人乱视频 | 久久不卡免费视频 | 日本欧美强乱视频在线 | 国产成人免费高清激情视频 | 成人一级黄色大片 | 美女班主任让我爽了一夜视频 | 色综合图片 | 国产a免费观看 | 日韩久久中文字幕 | 国产伦久视频免费观看视频 | 女同色图 | 久久九九亚洲精品 | pppd在线播放 | jizzjizz成熟丰满舒服 | 高清视频大片免费观看 | 特级毛片全部免费播放器 | 妇女澡堂淋浴性 | 丰满大屁股美女一级毛片 | 好男人天堂网 | 青草青草视频 | 国产综合亚洲专区在线 | 免费的强动漫人物 | 99久久国产综合精品网成人影院 | 九九精品视频一区二区三区 | 色美| gay18高中生白袜xnxx动漫 | 亚洲乱码一区二区三区国产精品 |