Java NIO通信基础示例详解

目录
  • Java NIO 通信基础介绍
    • NIO 和 OIO 的对比
    • 使用 FileChannel 完成文件复制的实践案例
    • 使用 DatagramChannel 数据包通道发送数据的实践案例
    • 使用 NIO 实现 Discard 服务器的实践案例

Java NIO 通信基础介绍

高性能的 Java 通信,绝对离不开 Java NIO 技术,现在主流的技术框架或中间件服务器,都使 用了 Java NIO 技术,譬如:Tomcat、Jetty、Netty。

Java NIO 由以下三个核心组件组成:

  • Channel(通道)
  • Buffer(缓冲区)
  • Selector(选择器)

NIO 和 OIO 的对比

在 Java 中,NIO 和 OIO 的区别,主要体现在三个方面:

  • OIO 是面向流(Stream Oriented)的,NIO 是面向缓冲区(Buffer Oriented)的。 何谓面向流,何谓面向缓冲区呢? OIO 是面向字节流或字符流的,在一般的 OIO 操作中,我们以流式的方式顺序地从一个流中读取一个或多个字节,因此,我们不能随意地改变读取指针的位置。而在 NIO 操作中则不同,NIO 中引入了 Channel(通道)和 Buffer(缓冲区)的概念。读取和写入,只需要从通道中读取数据到缓冲区中,或将数据从缓冲区中写入到通道中。NIO 不像 OIO 那样是顺序操作,可以随意地读取 Buffer 中任意位置的数据。
  • OIO 的操作是阻塞的,而 NIO 的操作是非阻塞的。 NIO 如何做到非阻塞的呢?大家都知道,OIO 操作都是阻塞的,例如,我们调用一个 read 方法读取一个文件的内容,那么调用 read 的线程会被阻塞住,直到 read 操作完成。 而在 NIO 的非阻塞模式中,当我们调用 read 方法时,如果此时有数据,则 read 读取数据并返回;如果此时没有数据,则 read 直接返回,而不会阻塞当前线程。NIO 的非阻塞,是如何做到的呢?NIO 使用了通道和通道的多路复用技术。
  • OIO 没有选择器(Selector)概念,而 NIO 有选择器的概念。 NIO 的实现,是基于底层的选择器的系统调用。NIO 的选择器,需要底层操作系统提供支持。 而 OIO 不需要用到选择器。

使用 FileChannel 完成文件复制的实践案例

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class MyCopyFile {
    private File inFile;
    private File outFile;
    private FileInputStream fis = null;
    private FileOutputStream fos = null;
    private FileChannel fisChannel = null;
    private FileChannel fosChannel = null;
    //复制文件
    public void copyFile(String srcPath, String destPath) throws IOException {
        try {
            inFile = new File(srcPath);
            outFile = new File(destPath);
            fis = new FileInputStream(inFile);
            fos = new FileOutputStream(outFile);
            fisChannel = fis.getChannel();
            fosChannel = fos.getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int length = -1;
            while ((length = fisChannel.read(buffer)) != -1) {
                buffer.flip();
                int outLenth = 0;
                while ((outLenth = fosChannel.write(buffer)) != 0) {
                    System.out.println("读取的字节数为:" + outLenth);
                }
                buffer.clear();
            }
            //强制刷新磁盘
            fosChannel.force(true);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            fosChannel.close();
            fos.close();
            fisChannel.close();
            fis.close();
        }
    }
    public static void main(String[] args) throws IOException {
        MyCopyFiletest = new MyCopyFile();
        String s1 = "D:\\maze.txt";
        String s2 = "D:\\maze1.txt";
        MyCopyFile.copyFile(s1, s2);
    }
}

使用 DatagramChannel 数据包通道发送数据的实践案例

功能:

获取用户的输入数据,通过 DatagramChannel 数据报通道,将数据发送到远程的服务器。

客户端代码:

public class Client {
    //Client发送信息
    public void send() throws IOException {
        DatagramChannel dChannel = DatagramChannel.open();
        dChannel.configureBlocking(false);
        ByteBuffer buf = ByteBuffer.allocate(1024);
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String s = sc.nextLine();
            buf.put(s.getBytes());
            buf.flip();
            dChannel.send(buf, new InetSocketAddress("127.0.0.1", 9999));
            buf.clear();
        }
        dChannel.close();
    }
    public static void main(String[] args) throws IOException {
        new Client().send();
    }
}

服务端代码:

public class Server {
    //服务端接收 用户发来的信息
    public void receive() throws IOException {
        DatagramChannel serverChannel = DatagramChannel.open();
        //设置成非阻塞模式
        serverChannel.configureBlocking(false);
        serverChannel.bind(new InetSocketAddress("127.0.0.1", 9999));
        Selector selector = Selector.open();
        serverChannel.register(selector, SelectionKey.OP_READ);
        while (selector.select() > 0) {
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (iterator.hasNext()) {
                SelectionKey next = iterator.next();
                if (next.isReadable()) {
                    SocketAddress receive = serverChannel.receive(buffer);
                    buffer.flip();
                    String s = new String(buffer.array(), 0, buffer.limit());
                    System.out.println(s);
                    buffer.clear();
                }
            }
            iterator.remove();
        }
        //关闭选择器和通道
        selector.close();
        serverChannel.close();
    }
    public static void main(String[] args) throws IOException {
        new Server().receive();
    }
}

使用 NIO 实现 Discard 服务器的实践案例

功能:

仅仅读取客户端通道的输入数据,读取完成后直接关闭客户端通道;并且读取到的数据直接抛弃掉

Discard 服务器代码:

public class SocketServerDemo {
    public void receive() throws IOException {
        //创建服务器的通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //设置为非阻塞模式
        serverSocketChannel.configureBlocking(false);
        //开启选择器
        Selector selector = Selector.open();
        //绑定链接
        serverSocketChannel.bind(new InetSocketAddress(9999));
        //将通道的某个IO事件  注册到选择器上
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        //轮询所有就绪的IO事件
        while (selector.select() > 0) {
            //逐个获取IO事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            //逐个判断该IO事件是否为想要的
            while (iterator.hasNext()) {
                SelectionKey next = iterator.next();
                if (next.isAcceptable()) {
                    //如果为该事件为“连接就绪”事件,就获取客户端的链接
                    SocketChannel clientSocket = serverSocketChannel.accept();
                    //将客户端的链接设置为非阻塞模式
                    clientSocket.configureBlocking(false);
                    //将新的通道的可读事件,注册到选择器上
                    clientSocket.register(selector, SelectionKey.OP_READ);
                } else if (next.isReadable()) {
                    //若IO事件为“可读事件”,读取数据
                    SocketChannel clientSocket = (SocketChannel) next.channel();
                    //创建缓冲区
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int length = 0;
                    //读取事件 让后丢弃
                    while ((length = clientSocket.read(buffer)) > 0) {
                        buffer.flip();
                        String s = new String(buffer.array(), 0, length);
                        System.out.println(s);
                        buffer.clear();
                    }
                    clientSocket.close();
                }
                //移除选择键
                iterator.remove();
            }
        }
        serverSocketChannel.close();
    }
    public static void main(String[] args) throws IOException {
        new SocketServerDemo().receive();
    }
}

客户端的 DiscardClient 代码:

public class SocketClientDemo {
    public void socketClient() throws IOException {
        SocketChannel clientSocket = SocketChannel.open(new InetSocketAddress(9999));
        //切换成非阻塞模式
        clientSocket.configureBlocking(false);
        //如果没有连接完成 就一直链接
        while (!clientSocket.finishConnect()){
        }
        //执行到这里说明已经连接完成了
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put("Hello SocketService".getBytes());
        buffer.flip();
        clientSocket.write(buffer);
        clientSocket.shutdownInput();
        clientSocket.close();
    }
    public static void main(String[] args) throws IOException {
        new SocketClientDemo().socketClient();
    }
}

与 Java OIO 相比,Java NIO 编程大致的特点如下:

(1)在 NIO 中,服务器接收新连接的工作,是异步进行的。不像 Java 的 OIO 那样,服务器监听连接,是同步的、阻塞的。NIO 可以通过选择器(也可以说成:多路复用器),后续不断地轮询选择器的选择键集合,选择新到来的连接。

(2)在 NIO 中,SocketChannel 传输通道的读写操作都是异步的。如果没有可读写的数据,负责 IO 通信的线程不会同步等待。这样,线程就可以处理其他连接的通道;不需要像 OIO 那样,线程一直阻塞,等待所负责的连接可用为止。

(3)在 NIO 中,一个选择器线程可以同时处理成千上万个客户端连接,性能不会随着客户端的增加而线性下降。

以上就是Java NIO通信基础示例详解的详细内容,更多关于Java NIO通信基础的资料请关注我们其它相关文章!

(0)

相关推荐

  • 浅析Java NIO 直接缓冲区和非直接缓冲区

    定义 以上是书<深入理解java虚拟机>对直接内存的描述.直接缓冲区用的就是直接内存. java nio字节缓冲区要么是直接的,要么是非直接的.如果为直接字节缓冲区,则java虚拟机会尽最大努力直接在此缓冲区上执行本机的IO操作,也就是说,在每次调用基础操作系统的一个本机IO操作前后,虚拟机都会尽量避免将内核缓冲区内容复制到用户进程缓冲区中,或者反过来,尽量避免从用户进程缓冲区复制到内核缓冲区中. 直接缓冲区可以通过调用该缓冲区类的allocateDirect(int capacity) 方法

  • Java NIO Buffer实现原理详解

    目录 1.Buffer的继承体系 2.Buffer的操作API使用案例 3.Buffer的基本原理 4.allocate方法初始化一个指定容量大小的缓冲区 5.slice方法缓冲区分片 6.只读缓冲区 7.直接缓冲区 8.内存映射 1.Buffer的继承体系 如上图所示,对于Java中的所有基本类型,都会有一个具体的Buffer类型与之对应,一般我们最经常使用的是ByteBuffer. 2.Buffer的操作API使用案例 举一个IntBuffer的使用案例: /** * @author csp

  • Java使用NIO优化IO实现文件上传下载功能

    目录 1 NIO的一些基础预备知识 2 NIO为何较传统的io速度较快 3 NIO实战上传下载 3.1 url下载文件 3.2 通过NIO上传文件 1 NIO的一些基础预备知识 Java中IO流类的体系中BIO与NIO:https://blog.csdn.net/ZGL_cyy/article/details/104326458Java IO体系与NIO和BIO体系面试题 :https://blog.csdn.net/ZGL_cyy/article/details/122836368为什么使用N

  • Java NIO 中 Selector 解析

    目录 一.Selector 简介 1.Selector 和 Channel 关系 2.可选择通道(SelectableChannel) 3.Channel 注册到 Selector 4.选择键(SelectionKey) 二.Selector 的使用方法 1.Selector 的创建 2.注册 Channel 到 Selector 3.轮训查询就绪操作 4.停止选择的方法 三.示例代码 1.服务端代码 2.客户端代码 3.NIO 编程步骤总结 一.Selector 简介 1.Selector 和

  • java.nio.file.WatchService 实时监控文件变化的示例代码

    目录 1.示例代码 2.其实并没有实时 在平时的开发过程中,会有很多场景需要实时监听文件的变化,如下:1.通过实时监控 mysql 的 binlog 日志实现数据同步2.修改配置文件后,希望系统可以实时感知3.应用系统将日志写入文件中,日志监控系统可以实时抓取日志,分析日志内容并进行报警4.类似 ide 工具,可以实时感知管理的工程下的文件变更 在 Java 语言中,从 JDK7 开始,新增了java.nio.file.WatchService类,用来实时监控文件的变化. 1.示例代码 File

  • Java NIO通信基础示例详解

    目录 Java NIO 通信基础介绍 NIO 和 OIO 的对比 使用 FileChannel 完成文件复制的实践案例 使用 DatagramChannel 数据包通道发送数据的实践案例 使用 NIO 实现 Discard 服务器的实践案例 Java NIO 通信基础介绍 高性能的 Java 通信,绝对离不开 Java NIO 技术,现在主流的技术框架或中间件服务器,都使 用了 Java NIO 技术,譬如:Tomcat.Jetty.Netty. Java NIO 由以下三个核心组件组成: Ch

  • Java NIO服务器端开发详解

    一.NIO类库简介 1.缓冲区Buffer Buffer是一个对象,包含一些要写入和读出的数据. 在NIO中,所有的数据都是用缓冲区处理的,读取数据时,它是从通道(Channel)直接读到缓冲区中,在写入数据时,也是从缓冲区写入到通道. 缓冲区实质上是一个数组,通常是一个字节数组(ByteBuffer),也可以是其它类型的数组,此外缓冲区还提供了对数据的结构化访问以及维护读写位置等信息. Buffer类的继承关系如下图所示: 2.通道Channel Channel是一个通道,网络数据通过Chan

  • JSON在Java中的相互转换示例详解

    什么是JSON? JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式. 易于人阅读和编写.同时也易于机器解析和生成. JSON采用完全独立于语言的文本格式,而且很多语言都提供了对json的支持(包括C, C++, C#, Java, JavaScript, Perl, Python等). 这样就使得JSON成为理想的数据交换格式. 数据交换格式,是指客户端和服务器之间通信,传递数据时,数据使用的格式是json JSON在java中的使用 json在ja

  • Java InheritableThreadLocal使用示例详解

    目录 引子 InheritableThreadLocal简单使用 InheritableThreadLocal原理分析 引子 public class InheritableThreadLocalDemo { private static ThreadLocal<String> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { threadLocal.set("mainT

  • 教你正确的Java扩展方法示例详解

    目录 引言 支持扩展方法的语言 C# Visual Basic Kotlin 主角登场 Lombok @ExtensionMethod Manifold 总结 引言 扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型.扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用.对于用 C# 和 Visual Basic 编写的客户端代码,调用扩展方法与调用在类型中实际定义的方法没有明显的差异. 支持扩展方法的语言 其实比较多的编程语言都支持了

  • Java NIO Buffer过程详解

    前言 在与NIO通道交互时使用Java NIO Buffer. 如您所知,数据从通道读入缓冲区,并从缓冲区写入通道. 缓冲区本质上是一个可以写入数据的内存块,然后可以再次读取. 此内存块包含在NIO Buffer对象中,该对象提供了一组方法,可以更轻松地使用内存块. 基本缓冲区用法 使用缓冲区读取和写入数据通常遵循这4个小步骤: 1.写入数据到缓冲区 2.调用 buffer.flip() 3.从缓冲区读取数据 4.调用 buffer.clear() 或者 buffer.compact() 当你将

  • Java NIO Selector用法详解【含多人聊天室实例】

    本文实例讲述了Java NIO Selector用法.分享给大家供大家参考,具体如下: 一.Java NIO 的核心组件 Java NIO的核心组件包括:Channel(通道),Buffer(缓冲区),Selector(选择器),其中Channel和Buffer比较好理解 简单来说 NIO是面向通道和缓冲区的,意思就是:数据总是从通道中读到buffer缓冲区内,或者从buffer写入到通道中. 关于Channel 和 Buffer的详细讲解请看:Java NIO 教程 二.Java NIO Se

  • JAVA构造函数(方法)示例详解

    目录  一.什么是构造函数 二.构造函数的特点 三.示例 四.默认构造函数 五.构造函数的重载 六.构造函数的使用 构造函数的特点 总结  一.什么是构造函数 Java构造函数,也叫构造方法,是JAVA中一种特殊的函数.与函数名相同,无返回值. 作用:一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象的属性和方法. 在现实生活中,很多事物一出现,就天生具有某些属性和行为.比如人一出生,就有年龄.身高.体重.就会哭:汽车一出产,就有颜色.有外观.可以运行等. 这些,我们就可以将这

  • java list用法示例详解

    |--List:元素是有序的(怎么存的就怎么取出来,顺序不会乱),元素可以重复(角标1上有个3,角标2上也可以有个3)因为该集合体系有索引,  |-- ArrayList:底层的数据结构使用的是数组结构(数组长度是可变的百分之五十延长)(特点是查询很快,但增删较慢)线程不同步  |-- LinkedList:底层的数据结构是链表结构(特点是查询较慢,增删较快)  |-- Vector:底层是数组数据结构 线程同步(数组长度是可变的百分之百延长)(无论查询还是增删都很慢,被ArrayList替代了

  • java反射机制示例详解

    1.什么是反射?一个类有多个组成部分,例如:成员变量,方法,构造方法等.反射就是加载类,并解剖出类的各个组成部分. 2.加载类java中有一个Class类用于代表某一个类的字节码.Class类既然代表某个类的字节码,那就要提供加载某个类字节码的方法:forName().   此方法用于加载某个类的字节码到内存中,并使用class对象进行封装.另外2种得到class对象的方式:类名.class对象.getClass() 先创建一个简单的Person类 复制代码 代码如下: public class

随机推荐