最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java基礎(chǔ)之NIO介紹及使用

 更新時(shí)間:2021年04月29日 09:18:30   作者:[1-9]\d*(.\d{1,2})?  
這篇文章主要介紹了java基礎(chǔ)之NIO介紹及使用,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下

一、NIO

java.nio全稱(chēng)java non-blocking IO,是指jdk1.4 及以上版本里提供的新api(New IO) ,為所有的原始類(lèi)型(boolean類(lèi)型除外)提供緩存支持的數(shù)據(jù)容器,使用它可以提供非阻塞式的高伸縮性網(wǎng)絡(luò)。

二、三大組件

NIO三大組件:Channel、Buffer、Selector

1.Channel 和Buffer

Channel是一個(gè)對(duì)象,可以通過(guò)它讀取和寫(xiě)入數(shù)據(jù)。拿 NIO 與原來(lái)的 I/O 做個(gè)比較,通道就像是流,而且他們面向緩沖區(qū)(Buffer)的。所有數(shù)據(jù)都通過(guò)Buffer對(duì)象來(lái)處理,永遠(yuǎn)不會(huì)將字節(jié)直接寫(xiě)入通道中,而是將數(shù)據(jù)寫(xiě)入包含一個(gè)或多個(gè)字節(jié)的緩沖區(qū)。也不會(huì)直接從通道中讀取字節(jié),而是將數(shù)據(jù)從通道讀入緩沖區(qū),再?gòu)木彌_區(qū)獲取這個(gè)字節(jié)。

Channel是讀寫(xiě)數(shù)據(jù)的雙向通道,可以從Channel將數(shù)據(jù)讀取Buffer,也可將Buffer的數(shù)據(jù)寫(xiě)入Channel,而之前的Stream要么是輸入(InputStream)、要么是輸出(OutputStream),只在一個(gè)方向上流通。 而通道(Channel)可以用于讀、寫(xiě)或者同時(shí)用于讀寫(xiě)

常見(jiàn)的Channel

1.FileChannel

2.DatagramChannel

3.SocketChannel

4.ServerSocketChannel

Buffer緩沖區(qū)用來(lái)讀寫(xiě)數(shù)據(jù),常見(jiàn)的Buffer

1.ByteBuffer

2.ShortBuffer

3.IntBuffer

4.LongBuffer

5.FloatBuffer

6.DoubleBuffer

7.CharBuffer

2.Selector

​ 在多線(xiàn)程模式下,阻塞IO時(shí),一個(gè)線(xiàn)程只能處理一個(gè)請(qǐng)求,比如http請(qǐng)求,當(dāng)請(qǐng)求響應(yīng)式關(guān)閉連接,釋放線(xiàn)程資源。Selector選擇器的作用就是配合一個(gè)線(xiàn)程來(lái)管理多個(gè)Channel,獲取這些Channel上發(fā)生的事件,這些Channel工作在非阻塞模式下,不會(huì)讓線(xiàn)程一直在一個(gè)Channel上,適合連接數(shù)特別多,但流量低的場(chǎng)景。

在這里插入圖片描述

調(diào)用Selector的select()方法會(huì)阻塞直到Channel發(fā)送了讀寫(xiě)就緒事件,這些事件發(fā)生,select()方法就會(huì)

返回這些事件交給thread來(lái)處理。

三、ByteBuffer的使用

屬性

Buffer的讀寫(xiě)操作就是通過(guò)改變position,mark,limit的值來(lái)實(shí)現(xiàn)。注意他們之間的關(guān)系可以很輕松的讀、寫(xiě)、覆蓋。

  • position:對(duì)于寫(xiě)入模式,表示當(dāng)前可寫(xiě)入數(shù)據(jù)的下標(biāo),對(duì)于讀取模式,表示接下來(lái)可以讀取的數(shù)據(jù)的下標(biāo)。當(dāng)前操作位置的下標(biāo)。position()方法獲取。
  • mark:用來(lái)標(biāo)志當(dāng)前操作位置,調(diào)用mark()方法,使mark = position,可以在讀和寫(xiě)切換過(guò)程中標(biāo)記前一個(gè)操作下標(biāo)位置。
  • limit:Buffer的限界值。對(duì)于寫(xiě)模式,相當(dāng)于可寫(xiě)入的最大值,數(shù)組長(zhǎng)度。對(duì)于讀模式,表示最多可以讀取的數(shù)據(jù)的位置下標(biāo),通過(guò)flip()方法進(jìn)行讀寫(xiě)切換,原理改變position,mark,limit的值。
  • capacity:數(shù)組容量大小

方法

Buffer的方法全是根據(jù)改變position的值進(jìn)行操作的。

  • put():put方法寫(xiě)入數(shù)據(jù),可以單個(gè)byte字節(jié),或者byte數(shù)組。或者其它類(lèi)型,根據(jù)Buffer實(shí)例而定。
  • get():get方法讀取數(shù)據(jù),可以傳入byte數(shù)組和不傳參讀取一個(gè)字節(jié)。
  • mark():標(biāo)記當(dāng)前下標(biāo)position位置,mark = position 。讀寫(xiě)操作切換或者特殊要求時(shí),標(biāo)記當(dāng)前的下標(biāo)位置。
  • reset():將position 值重置為mark()方法標(biāo)記的值。
  • array():Buffer內(nèi)數(shù)據(jù)的byte數(shù)組。沒(méi)有值的位用0補(bǔ)位。
  • flip():limit為position值,將position置為0,mark初始值,寫(xiě)入操作切換為讀操作。
  • rewind():將position 和 mark設(shè)為初始值,調(diào)用這個(gè)可以一直讀取內(nèi)容或者一直寫(xiě)入覆蓋之前內(nèi)容,從第一位開(kāi)始讀/寫(xiě)。
  • clear():將屬性值還原。之前array()數(shù)組的值還在。
  • hasRemaining():判斷是否到最后

四、測(cè)試Demo

private static void buffer1() {
    String data = "abc";
    //byte[] bytes = new byte[1024];
    //創(chuàng)建一個(gè)字節(jié)緩沖區(qū),1024byte
    ByteBuffer byteBuffer = ByteBuffer.allocate(15);
    System.out.println(byteBuffer.toString());
    // 標(biāo)記當(dāng)前下標(biāo)position位置,mark = position ,返回當(dāng)前對(duì)象
    System.out.println(byteBuffer.mark());
    //對(duì)于寫(xiě)入模式,表示當(dāng)前可以寫(xiě)入的數(shù)組大小,默認(rèn)為數(shù)組的最大長(zhǎng)度,對(duì)于讀取模式,表示當(dāng)前最多可以讀取的數(shù)據(jù)的位置下標(biāo)
    System.out.println(byteBuffer.limit());
    // 對(duì)于寫(xiě)入模式,表示當(dāng)前可寫(xiě)入數(shù)據(jù)的下標(biāo),對(duì)于讀取模式,表示接下來(lái)可以讀取的數(shù)據(jù)的下標(biāo)
    System.out.println(byteBuffer.position());
    //capacity 表示當(dāng)前數(shù)組的容量大小
    System.out.println(byteBuffer.capacity());
    //將字節(jié)數(shù)據(jù)寫(xiě)入 byteBuffer
    byteBuffer.put(data.getBytes());
    //保存了當(dāng)前寫(xiě)入的數(shù)據(jù)
    for(Byte b : byteBuffer.array()){
        System.out.print(b + " ");
    }
    System.out.println();
    System.out.println(new String(byteBuffer.array()));
    //讀寫(xiě)模式切換 改變 limit,position ,mark的值
    byteBuffer.flip();
    //切換為寫(xiě)模式,將第一個(gè)字節(jié)覆蓋
    byteBuffer.put("n".getBytes()); // abc 改為 nbc
    System.out.println(new String(byteBuffer.array()));
    //讓position為之前標(biāo)記的值,調(diào)用mark()方法是將mark = position,這里將position = mark,mark為初始值拋出異常
    byteBuffer.mark();
    byteBuffer.reset();
    //將position 和 mark設(shè)為初始值,調(diào)用這個(gè)可以一直讀取內(nèi)容或者一直寫(xiě)入覆蓋之前內(nèi)容,從第一位開(kāi)始讀/寫(xiě)
    byteBuffer.rewind();
    for(Byte b : byteBuffer.array()){
        System.out.print(b + " ");
    }
    System.out.println();
    System.out.println(byteBuffer.toString());
    //找到可寫(xiě)入的開(kāi)始位置,不覆蓋之前的數(shù)據(jù)
    byteBuffer.compact();
    System.out.println(byteBuffer.toString());
}

寫(xiě)入讀取完整操作

private static void buffer(){
    //寫(xiě)入的數(shù)據(jù)
    String data = "1234";
    //創(chuàng)建一個(gè)字節(jié)緩沖區(qū),1024byte
    ByteBuffer byteBuffer = ByteBuffer.allocate(15);
    //寫(xiě)入數(shù)據(jù)
    byteBuffer.put(data.getBytes());
    //打輸出 49 50 51 52 0 0 0 0 0 0 0 0 0 0 0
    println(byteBuffer.array());
    byteBuffer.put((byte) 5);
    //追加寫(xiě)入 輸出: 49 50 51 52 5 0 0 0 0 0 0 0 0 0 0
    println(byteBuffer.array());
    //覆蓋寫(xiě)入
    byteBuffer.flip(); //將寫(xiě)入下標(biāo)的 position = 0
    byteBuffer.put((byte) 1);
    byteBuffer.put((byte) 2);
    byteBuffer.put((byte) 3);
    byteBuffer.put((byte) 4);
    byteBuffer.put((byte) 5);
    // 打印輸出 : 1 2 3 4 5 0 0 0 0 0 0 0 0 0 0
    println(byteBuffer.array());
    //讀取數(shù)據(jù)操作
    byteBuffer.flip();//從頭開(kāi)始讀
    while (byteBuffer.position() != byteBuffer.limit()){
        System.out.println(byteBuffer.get());
    }
    //此時(shí) position 和 數(shù)據(jù)數(shù) limit相等
    System.out.println(byteBuffer.toString());

    //批量讀取
    byteBuffer.flip(); //將 position 置位0,從頭開(kāi)始操作
    //創(chuàng)建一個(gè)byte數(shù)組,數(shù)組大小為可讀取的大小
    byte[] bytes = new byte[byteBuffer.limit()];
    byteBuffer.get(bytes);
    //輸出bytes 1 2 3 4 5
    println(bytes);
}

 private static void println(byte[] bytes){
     for(Byte b : bytes){
         System.out.print(b + " ");
     }
     System.out.println();
}

字符串跟ByteBuffer之間的轉(zhuǎn)換

public static void main(String[] args) {

    /*======================字符串轉(zhuǎn)buffer===========================*/
    //1.字符串 轉(zhuǎn)為buytebuffer 需要轉(zhuǎn)為讀模式再進(jìn)行讀取操作
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    buffer.put("nio".getBytes());

    //2.charset  自動(dòng)轉(zhuǎn)為讀模式
    ByteBuffer buffer1 = StandardCharsets.UTF_8.encode("nio");

    //3, warp 自動(dòng)轉(zhuǎn)為讀模式
    ByteBuffer buffer2 = ByteBuffer.wrap("nio".getBytes());

    /*======================buffer轉(zhuǎn)字符串===========================*/
    String str = StandardCharsets.UTF_8.decode(buffer1).toString();
    System.out.println(str);
}

五、Channel的使用

文件編程FileChannel

FileChannel只能工作在阻塞模式下,不能配合在Selector使用,Channel是雙向通道,但是FileChannel根據(jù)獲取源頭判定可讀或可寫(xiě)

  • FileInputStream獲取,只可讀
  • FileOutputStream獲取,只可寫(xiě)
  • RandomAccessFile獲取,可讀、可寫(xiě)(雙向通道)
**
 * 文件流對(duì)象打開(kāi)Channel,F(xiàn)ileChannel是阻塞的
 * @throws Exception
 */
private static void channel() throws Exception{
    FileInputStream in = new FileInputStream("C:\\Users\\zqq\\Desktop\\123.txt");
    FileOutputStream out = new FileOutputStream("C:\\Users\\zqq\\Desktop\\321.txt");
    //通過(guò)文件輸入流創(chuàng)建通道channel
    FileChannel channel = in.getChannel();
    //獲取FileChannel
    FileChannel outChannel = out.getChannel();
    //創(chuàng)建緩沖區(qū)byteBuffer
    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
    //將管道channel中數(shù)據(jù)讀取緩存區(qū)byteBuffer中,channel只能與Buffer交互
    while (channel.read(byteBuffer) != -1){
        //position設(shè)置為0,從頭開(kāi)始讀
        byteBuffer.flip();
        outChannel.write(byteBuffer);
        //byteBuffer 屬性還原
        byteBuffer.clear();
    }
    //關(guān)閉各種資源
    channel.close();
    out.flush();
    out.close();
    in.close();
    out.close();
}
/**
 * 靜態(tài)方法打開(kāi)Channel
 * @throws Exception
 */
public static void channel1() throws Exception{
    // StandardOpenOption.READ :讀取一個(gè)已存在的文件,如果不存在或被占用拋出異常
    // StandardOpenOption.WRITE :以追加到文件頭部的方式,寫(xiě)入一個(gè)已存在的文件,如果不存在或被占用拋出異常
    // StandardOpenOption.APPEND:以追加到文件尾部的方式,寫(xiě)入一個(gè)已存在的文件,如果不存在或被占用拋出異常
    // StandardOpenOption.CREATE:創(chuàng)建一個(gè)空文件,如果文件存在則不創(chuàng)建
    // StandardOpenOption.CREATE_NEW:創(chuàng)建一個(gè)空文件,如果文件存在則報(bào)錯(cuò)
    // StandardOpenOption.DELETE_ON_CLOSE:管道關(guān)閉時(shí)刪除文件
    //創(chuàng)建讀通道
    FileChannel inChannel = FileChannel.open(Paths.get("C:\\Users\\zqq\\Desktop\\123.txt"), StandardOpenOption.READ);
    FileChannel outChannel = FileChannel.open(Paths.get("C:\\Users\\zqq\\Desktop\\321.txt"),
            StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);

    //內(nèi)存映射
    MappedByteBuffer inByteBuffer = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
    MappedByteBuffer outByteBuffer = outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());

    //直接對(duì)緩沖區(qū)數(shù)據(jù)讀寫(xiě)
    byte[] bytes = new byte[inByteBuffer.limit()];
    inByteBuffer.get(bytes);//讀取inByteBuffer內(nèi)的數(shù)據(jù),讀到bytes數(shù)組中
    outByteBuffer.put(bytes);//寫(xiě)入到outByteBuffer
    inChannel.close();
    outChannel.close();
}

RandomAccessFile打開(kāi)通道Channel

/**
 * 通過(guò)RandomAccessFile獲取雙向通道
 * @throws Exception
 */
private static void random() throws Exception{
    try (RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\workspace\\Demo\\test.txt","rw")){
        //獲取Channel
        FileChannel fileChannel = randomAccessFile.getChannel();
        //截取字節(jié)
        //fileChannel.truncate(10);
        //創(chuàng)建ByteBuffer,注意文件大小
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        fileChannel.read(byteBuffer);
        System.out.println(new String(byteBuffer.array(),"GBK"));
        byteBuffer.clear();
        String data = "this is data\r";
        byteBuffer.put(data.getBytes());
        byteBuffer.flip();//讀寫(xiě)切換
        while (byteBuffer.hasRemaining()){
            fileChannel.write(byteBuffer);
        }
        //將通道數(shù)據(jù)強(qiáng)制寫(xiě)到磁盤(pán)
        fileChannel.force(true);
    }
}

FileChannel數(shù)據(jù)傳輸transferTo

/**
 * 一個(gè)文件向另一個(gè)文件傳輸(copy)
 */
private static void transferTo() {
    try (
            FileChannel inChannel = new FileInputStream("C:\\Users\\44141\\Desktop\\demo\\in.txt").getChannel();
            FileChannel outChannel = new FileOutputStream("C:\\Users\\44141\\Desktop\\demo\\out.txt").getChannel()
    ){
        //底層使用操作系統(tǒng)零拷貝進(jìn)行優(yōu)化,效率高。限制2g
        inChannel.transferTo(0,inChannel.size(),outChannel);
    }catch (Exception e){
        e.printStackTrace();
    }
}

/**
 * 大于2g數(shù)據(jù)
 */
private static void transferToGt2g() {
    try (
            FileChannel inChannel = new FileInputStream("C:\\Users\\44141\\Desktop\\demo\\in.txt").getChannel();
            FileChannel outChannel = new FileOutputStream("C:\\Users\\44141\\Desktop\\demo\\out1.txt").getChannel()
    ){
        //記錄inChannel初始化大小
        long size = inChannel.size();
        //多次傳輸
        for(long rsize = size; rsize > 0;){
            //transferTo返回位移的字節(jié)數(shù)
            rsize -= inChannel.transferTo((size-rsize),rsize,outChannel);
        }
    }catch (Exception e){
        e.printStackTrace();
    }
}

六、網(wǎng)絡(luò)編程

阻塞模式

阻塞模式服務(wù)端每個(gè)方法都會(huì)阻塞等待客戶(hù)端操作。比如accept()方法阻塞等待客戶(hù)端連接,read()方法阻塞等待客戶(hù)端傳送數(shù)據(jù),并發(fā)訪(fǎng)問(wèn)下沒(méi)法高效的進(jìn)行工作。

1.服務(wù)端代碼

private static void server() throws Exception{

    //1.創(chuàng)建服務(wù)器
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

    //2.綁定監(jiān)聽(tīng)端口
    serverSocketChannel.bind(new InetSocketAddress(8080));

    while (true){
        System.out.println("開(kāi)始監(jiān)聽(tīng)連接=============" );
        //4.accept 監(jiān)聽(tīng)進(jìn)來(lái)的連接 返回SocketChannel對(duì)象,accept默認(rèn)阻塞
        SocketChannel socketChannel = serverSocketChannel.accept();
        System.out.println("有連接連入===============" );
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        // read()是阻塞方法,等客戶(hù)端發(fā)送數(shù)據(jù)才會(huì)執(zhí)行
        socketChannel.read(byteBuffer);
        byteBuffer.flip();
        String str = StandardCharsets.UTF_8.decode(byteBuffer).toString();
        System.out.println("接收到數(shù)據(jù)=============:" + str);
    }
}

2.客戶(hù)端代碼

private static void client() throws Exception {
    //1.創(chuàng)建客戶(hù)端
    SocketChannel socketChannel = SocketChannel.open();
    //連接服務(wù)端
    socketChannel.connect(new InetSocketAddress("localhost",8080));
    //2 秒后寫(xiě)入數(shù)據(jù)
    Thread.sleep(2 * 1000);
    socketChannel.write(StandardCharsets.UTF_8.encode("nio"));
    System.out.println();
}

非阻塞模式

服務(wù)端設(shè)置成非阻塞模式。客戶(hù)端不用動(dòng)。

private static void server() throws Exception{

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

    //設(shè)置成非阻塞模式
    serverSocketChannel.configureBlocking(false);
    serverSocketChannel.bind(new InetSocketAddress(8080));
    while (true){
        SocketChannel socketChannel = serverSocketChannel.accept();
        //非阻塞模式下,SocketChannel會(huì)返回為null
        if(socketChannel != null){
            //非阻塞模式
            socketChannel.configureBlocking(false);
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            socketChannel.read(byteBuffer);
            byteBuffer.flip();
            String str = StandardCharsets.UTF_8.decode(byteBuffer).toString();
            System.out.println("接收到數(shù)據(jù)=============:" + str);
        }
    }
}

七、Selector

Selector選擇器的作用就是配合一個(gè)線(xiàn)程來(lái)管理多個(gè)Channel,被Selector管理的Channel必須是非阻塞模式下的,所以Selector沒(méi)法與FileChannel(FileChannel只有阻塞模式)一起使用。

創(chuàng)建Selector

創(chuàng)建Selector只需要調(diào)用一個(gè)靜態(tài)方法

//創(chuàng)建Selector
Selector selector = Selector.open();

Selector可以用來(lái)監(jiān)聽(tīng)Channel的事件,總共有四個(gè)事件:

  • accept:會(huì)在有連接請(qǐng)求時(shí)觸發(fā),靜態(tài)常量 SelectionKey.OP_ACCEPT
  • connect:客戶(hù)端建立連接后觸發(fā),靜態(tài)常量 SelectionKey.OP_CONNECT
  • read:可讀時(shí)觸發(fā),靜態(tài)常量 SelectionKey.OP_READ
  • write:可寫(xiě)時(shí)觸發(fā),靜態(tài)常量 SelectionKey.OP_WRITE

Selector與Channel綁定

//設(shè)置成非阻塞模式
serverSocketChannel.configureBlocking(false);
SelectionKey selectionKey = serverSocketChannel.register(selector,0,null);
//綁定關(guān)注的事件
selectionKey.interestOps(SelectionKey.OP_ACCEPT);

八、網(wǎng)絡(luò)編程(多路復(fù)用)

1.客戶(hù)端代碼 SocketChannel

public static void main(String[] args) throws Exception {
    client();

}

private static void client() throws Exception {
    //1.創(chuàng)建客戶(hù)端
    SocketChannel socketChannel = SocketChannel.open();
    //連接服務(wù)端
    socketChannel.connect(new InetSocketAddress("localhost",8080));
    //2 秒后寫(xiě)入數(shù)據(jù)
    Thread.sleep(2 * 1000);
    socketChannel.write(StandardCharsets.UTF_8.encode("nio"));
    //3.讀取服務(wù)端返回?cái)?shù)據(jù)
    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
    socketChannel.read(byteBuffer);
    byteBuffer.flip();
    System.out.println("服務(wù)端返回?cái)?shù)據(jù)=======:" + StandardCharsets.UTF_8.decode(byteBuffer).toString());
    //斷開(kāi)連接
    socketChannel.close();
}

2.服務(wù)端代碼

public static void main(String[] args) throws Exception{
    server();
}

private static void server() throws Exception{
    //創(chuàng)建Selector
    Selector selector = Selector.open();
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    //設(shè)置成非阻塞模式
    serverSocketChannel.configureBlocking(false);
    //將Channel注冊(cè)到selector上(綁定關(guān)系)
    //當(dāng)事件發(fā)生后可以根據(jù)SelectionKey知道哪個(gè)事件和哪個(gè)Channel的事件
    SelectionKey selectionKey = serverSocketChannel.register(selector,0,null);
    //selectionKey 關(guān)注ACCEPT事件(也可以在上面注冊(cè)時(shí)用第二個(gè)參數(shù)設(shè)置)
    selectionKey.interestOps(SelectionKey.OP_ACCEPT);
    serverSocketChannel.bind(new InetSocketAddress(8080));
    while (true){
        System.out.println("阻塞====================");
        // select方法沒(méi)有事件發(fā)生時(shí)阻塞線(xiàn)程,有事件線(xiàn)程會(huì)恢復(fù)運(yùn)行
        selector.select();
        System.out.println("開(kāi)始處理事件=================");
        // 處理事件
        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
        while (iterator.hasNext()){
            SelectionKey sk = iterator.next();
            //獲取到SelectionKey對(duì)象之后,將集合內(nèi)的引用刪掉(Selecotr不會(huì)自動(dòng)刪除)
            iterator.remove();
            //取消事件,不操作(不處理或者不取消事件,selector.select()方法不會(huì)阻塞)
            //sk.cancel();
            //區(qū)分不同的事件做不同的動(dòng)作
            if(sk.isAcceptable()){ //有連接請(qǐng)求事件
                //通過(guò)SelectionKey 獲取對(duì)應(yīng)的channel
                ServerSocketChannel channel = (ServerSocketChannel) sk.channel();
                SocketChannel socketChannel = channel.accept();
                socketChannel.configureBlocking(false);
                //讀取數(shù)據(jù)內(nèi)容,bytebuffer大小注意消息邊界(一個(gè)字符串被分割讀取多次出來(lái)結(jié)果不準(zhǔn)確)
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                //將socketChannel綁定Selector
                SelectionKey socketKey = socketChannel.register(selector,0,byteBuffer);
                //關(guān)注可讀事件
                socketKey.interestOps(SelectionKey.OP_READ);
            }else if(sk.isReadable()){//可讀事件
                try {
                    //取到Channel
                    SocketChannel socketChannel = (SocketChannel) sk.channel();
                    //獲取到綁定的ByteBuffer
                    ByteBuffer byteBuffer = (ByteBuffer) sk.attachment();
                    int read = socketChannel.read(byteBuffer);
                    //如果是正常斷開(kāi) read = -1
                    if(read == -1){
                        //取消事件
                        sk.cancel();
                        continue;
                    }
                    byteBuffer.flip();
                    String str = StandardCharsets.UTF_8.decode(byteBuffer).toString();
                    System.out.println("服務(wù)端讀取到數(shù)據(jù)===========:" + str);
                    //寫(xiě)數(shù)據(jù)回客戶(hù)端
                    ByteBuffer writeBuffer = StandardCharsets.UTF_8.encode("this is result");
                    socketChannel.write(writeBuffer);
                    //如果數(shù)據(jù)一次沒(méi)寫(xiě)完關(guān)注可寫(xiě)事件進(jìn)行再次寫(xiě)入(大數(shù)據(jù)一次寫(xiě)不完的情況)
                    if(writeBuffer.hasRemaining()){
                        //關(guān)注可寫(xiě)事件,添加事件,用interestOps()方法獲取到之前的事件加上可寫(xiě)事件(類(lèi)似linux系統(tǒng)的賦權(quán)限 777)
                        sk.interestOps(sk.interestOps() + SelectionKey.OP_WRITE);
                        sk.attach(writeBuffer);
                        //位運(yùn)算符也可以
                        //sk.interestOps(sk.interestOps() | SelectionKey.OP_WRITE);
                    }
                }catch (IOException e){
                    e.printStackTrace();
                    //客戶(hù)端異常斷開(kāi)連接 ,取消事件
                    sk.cancel();
                }
            }else if(sk.isWritable()){
                //取到Channel
                SocketChannel socketChannel = (SocketChannel) sk.channel();
                //獲取到綁定的ByteBuffer
                ByteBuffer writeBuffer = (ByteBuffer) sk.attachment();
                socketChannel.write(writeBuffer);
                //如果全部寫(xiě)完,取消可寫(xiě)事件綁定,解除writeBuffer綁定
                if(!writeBuffer.hasRemaining()){
                    sk.attach(null);
                    //取消可寫(xiě)事件
                    sk.interestOps(sk.interestOps() - SelectionKey.OP_WRITE);
                }
            }
        }
    }
}

到此這篇關(guān)于java基礎(chǔ)之NIO介紹及使用的文章就介紹到這了,更多相關(guān)Java NIO詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • drools中使用function的方法小結(jié)

    drools中使用function的方法小結(jié)

    當(dāng)我們?cè)赿rools中編寫(xiě)規(guī)則時(shí),有些時(shí)候存在重復(fù)的代碼,那么我們是否可以將這些重復(fù)代碼抽取出來(lái),封裝成一個(gè)function來(lái)調(diào)用呢?那么在drools中如何自定義function?下面小編給大家介紹下drools中使用function的方法,需要的朋友可以參考下
    2022-05-05
  • springboot接收日期字符串參數(shù)與返回日期字符串類(lèi)型格式化

    springboot接收日期字符串參數(shù)與返回日期字符串類(lèi)型格式化

    這篇文章主要介紹了springboot接收日期字符串參數(shù)與返回日期字符串類(lèi)型格式化,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java 8實(shí)現(xiàn)任意參數(shù)的單鏈表

    Java 8實(shí)現(xiàn)任意參數(shù)的單鏈表

    這篇文章主要為大家詳細(xì)介紹了Java 8實(shí)現(xiàn)任意參數(shù)的單鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • java關(guān)鍵字abstract(抽象)實(shí)例詳解

    java關(guān)鍵字abstract(抽象)實(shí)例詳解

    在Java中,抽象類(lèi)是不能實(shí)例化的類(lèi),它通常作為其他子類(lèi)的父類(lèi)存在,并提供了一種繼承的框架,抽象類(lèi)中可以包含抽象方法,這些方法沒(méi)有具體的實(shí)現(xiàn),必須由子類(lèi)來(lái)提供,本文給大家介紹java關(guān)鍵字abstract(抽象)實(shí)例詳解,感興趣的朋友跟隨小編一起看看吧
    2024-10-10
  • Mybatis注解方式完成輸入?yún)?shù)為list的SQL語(yǔ)句拼接方式

    Mybatis注解方式完成輸入?yún)?shù)為list的SQL語(yǔ)句拼接方式

    這篇文章主要介紹了Mybatis注解方式完成輸入?yún)?shù)為list的SQL語(yǔ)句拼接方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 淺談Spring AOP中args()和argNames的含義

    淺談Spring AOP中args()和argNames的含義

    這篇文章主要介紹了Spring AOP中args()和argNames的含義,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 用java實(shí)現(xiàn)掃雷游戲

    用java實(shí)現(xiàn)掃雷游戲

    這篇文章主要為大家詳細(xì)介紹了用java實(shí)現(xiàn)掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • spring cloud 分布式鏈路追蹤的方法

    spring cloud 分布式鏈路追蹤的方法

    這篇文章主要介紹了spring cloud 分布式鏈路追蹤的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • java?stream使用指南之sorted使用及進(jìn)階方式

    java?stream使用指南之sorted使用及進(jìn)階方式

    這篇文章主要介紹了java?stream使用指南之sorted使用及進(jìn)階方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • java判斷http地址是否連通(示例代碼)

    java判斷http地址是否連通(示例代碼)

    這篇文章通過(guò)實(shí)例代碼給大家介紹了java判斷http地址是否連通,文末給大家補(bǔ)充知識(shí)點(diǎn)url.openconnection() 設(shè)置超時(shí)時(shí)間的方法,感興趣的朋友跟隨小編一起看看吧
    2021-12-12

最新評(píng)論

秭归县| 南召县| 弥渡县| 疏附县| 黔东| 拉萨市| 凤阳县| 忻城县| 云龙县| 合山市| 栾川县| 南丹县| 师宗县| 祥云县| 偃师市| 镇平县| 祁阳县| 屯昌县| 封开县| 修文县| 晋中市| 崇左市| 柏乡县| 汕头市| 东港市| 宣化县| 海晏县| 崇信县| 习水县| 左云县| 应城市| 阿克| 达孜县| 桦甸市| 曲阳县| 莱州市| 大洼县| 平邑县| 苏尼特右旗| 通州区| 石河子市|