• Java NIO基本使用介绍


    NIO主要包括Channel,Buffer,Selector三个核心元素组成。

    Channel即通道,l和Buffer有好几种类型。下面是JAVA NIO中的一些主要Channel的实现:

    • FileChannel
    • DatagramChannel
    • SocketChannel
    • ServerSocketChannel

    正如你所看到的,这些通道涵盖了UDP 和 TCP 网络IO,以及文件IO。

    Buffer有IntBuffer,CharBuffer,FloatBuffer。。。。。

    可以在Selector上注册通道。

    Selector所在线程负责处理监听,待所关注的事件到达时,将事件分发给在Selector上注册的channel作异步处理,如下图所示。

    Buffer的基本用法

    使用Buffer读写数据一般遵循以下四个步骤:

    1. 调用channel的read()方法,将channel中的数据写入到Buffer中。
    2. 调用flip()方法 

      flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

      换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。

      public final Buffer flip() {
          limit = position;
          position = 0;
          mark = -1;
          return this;
      }
    3. 调用channel的write()方法,将Buffer中的数据写入channel中。
    4. 调用clear()方法或者compact()方法

    为了理解Buffer的工作原理,需要熟悉它的三个属性:

    • capacity
    • position
    • limit

    position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。

    这里有一个关于capacity,position和limit在读写模式中的说明,详细的解释在插图后面。

    capacity

    作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

    position

    当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.

    当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

    limit

    在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。

    当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

    使用JAVA NIO编写一个客户端与服务端通信的例子。

     Server

     1 package com.nio;
     2 
     3 import java.io.IOException;
     4 import java.net.InetSocketAddress;
     5 import java.nio.ByteBuffer;
     6 import java.nio.channels.SelectionKey;
     7 import java.nio.channels.Selector;
     8 import java.nio.channels.ServerSocketChannel;
     9 import java.nio.channels.SocketChannel;
    10 import java.util.Iterator;
    11 import java.util.Set;
    12 
    13 public class Server {
    14     private Selector selector;
    15     private ByteBuffer readBuffer = ByteBuffer.allocate(100);
    16 
    17     public void start() throws IOException {
    18         ServerSocketChannel ssc = ServerSocketChannel.open();
    19         ssc.configureBlocking(false);
    20         ssc.socket().bind(new InetSocketAddress("localhost", 8002));
    21         selector = Selector.open();
    22         ssc.register(selector, SelectionKey.OP_ACCEPT);
    23         while (!Thread.currentThread().isInterrupted()) {
    24             selector.select();
    25             Set selectedKeys = selector.selectedKeys();
    26             Iterator iterator = selectedKeys.iterator();
    27             while (iterator.hasNext()) {
    28                 SelectionKey key = (SelectionKey) iterator.next();
    29                 if (!key.isValid()) {
    30                     continue;
    31                 }
    32                 if (key.isAcceptable()) {
    33                     accept(key);
    34                 } else if (key.isReadable()) {
    35                     read(key);
    36                 }
    37             }
    38             iterator.remove();
    39         }
    40     }
    41 
    42     private void read(SelectionKey key) throws IOException {
    43         SocketChannel socketChannel = (SocketChannel) key.channel();
    44         this.readBuffer.clear();
    45         int readNum = 0;
    46         try {
    47             readNum = socketChannel.read(this.readBuffer);
    48         } catch (IOException e) {
    49             key.cancel();
    50             socketChannel.close();
    51             return;
    52         }
    53         if (readNum > 0) {
    54             byte[] newBytes = new byte[readNum];
    55             System.arraycopy(readBuffer.array(), 0, newBytes, 0, readNum);
    56             String message = new String(newBytes);
    57             System.out.println(message);
    58             message = "你好,已收到你发的消息:" + message;
    59             readBuffer.flip();
    60             readBuffer = ByteBuffer.wrap(message.getBytes());
    61             socketChannel.write(readBuffer);
    62         }
    63     }
    64 
    65     private void accept(SelectionKey key) throws IOException {
    66         ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
    67         SocketChannel clientChanel = ssc.accept();
    68         clientChanel.configureBlocking(false);
    69         clientChanel.register(selector, SelectionKey.OP_READ);
    70         System.out.println("a new client connected...");
    71     }
    72 
    73     public static void main(String[] args) throws IOException {
    74         new Server().start();
    75     }
    76 }

     Client

     1 package com.nio;
     2 
     3 import java.io.IOException;
     4 import java.net.InetSocketAddress;
     5 import java.nio.ByteBuffer;
     6 import java.nio.channels.SelectionKey;
     7 import java.nio.channels.Selector;
     8 import java.nio.channels.SocketChannel;
     9 import java.util.Iterator;
    10 import java.util.Scanner;
    11 import java.util.Set;
    12 
    13 public class Client {
    14     private void start() throws IOException {
    15         SocketChannel sc = SocketChannel.open();
    16         sc.configureBlocking(false);
    17         sc.connect(new InetSocketAddress("localhost", 8002));
    18         Selector selector = Selector.open();
    19         sc.register(selector, SelectionKey.OP_CONNECT );
    20         Scanner scanner = new Scanner(System.in);
    21         while (true) {
    22             selector.select();
    23             Set selectedKeys = selector.selectedKeys();
    24             Iterator iterator = selectedKeys.iterator();
    25             while (iterator.hasNext()) {
    26                 SelectionKey key = (SelectionKey) iterator.next();
    27                 if (key.isConnectable()) {
    28                     sc.finishConnect();
    29                     sc.register(selector, SelectionKey.OP_WRITE);
    30                     System.out.println("server connected");
    31                     break;
    32                 } else if (key.isWritable()) {
    33                     System.out.println("please input message");
    34                     String message = scanner.nextLine();
    35                     ByteBuffer writebufBuffer = ByteBuffer.wrap(message.getBytes());
    36                     sc.write(writebufBuffer);
    37                     sc.register(selector, SelectionKey.OP_READ);
    38                 }else if(key.isReadable()){
    39                     ByteBuffer readBuffer = ByteBuffer.allocate(1024);
    40                     int readNum = sc.read(readBuffer);
    41                     byte[] newBytes = new byte[readNum];
    42                     System.arraycopy(readBuffer.array(), 0, newBytes, 0, readNum);
    43                     String message = new String(newBytes);
    44                     System.out.println(message);
    45                     sc.register(selector, SelectionKey.OP_WRITE);
    46                 }
    47             }
    48             iterator.remove();
    49         }
    50     }
    51 
    52     public static void main(String[] args) throws IOException {
    53         new Client().start();
    54     }
    55 }

    Client端输入abc后,Server端会将收到的信息返回到Client端,打印"你好,已收到......"

    Server端也会打印出Client端发送的消息。

  • 相关阅读:
    Docker 安装 MySQL
    Docker安装
    Thymeleaf语法总结
    SpringBoot总结之事务和AOP
    SpringBoot总结之Spring Data Jpa
    SpringBoot总结之属性配置
    Spring总结之SpringMvc下
    Spring总结之SpringMvc上
    Spring总结之事务
    在什么情况下使用@ResponseBody 注解?
  • 原文地址:https://www.cnblogs.com/pingh/p/3222043.html
Copyright © 2020-2023  润新知