我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JavaNIO通信基础示例详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JavaNIO通信基础示例详解

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 class="lazy" data-srcPath, String destPath) throws IOException {
        try {
            inFile = new File(class="lazy" data-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通信基础的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JavaNIO通信基础示例详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JavaNIO通信基础示例详解

这篇文章主要为大家介绍了JavaNIO通信基础使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-26

Java基础元注解基本原理示例详解

这篇文章主要为大家介绍了Java基础元注解基本原理示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-17

Promise抛出错误解决基础示例详解

这篇文章主要为大家介绍了Promise抛出错误解决基础示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-15

python基础pandas的drop()用法示例详解

这篇文章主要介绍了python基础pandas的drop()用法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-15

Flutter与WebView通信方案示例详解

这篇文章主要为大家介绍了Flutter与WebView通信方案示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-04

Linux基础命令---ipcs显示进程通信

ipcsipcs指令用来显示进程间通信状况。“-i”选项允许指定特定的资源id。将只打印有关此id的信息。此命令的适用范围:RedHat、RHEL、Ubuntu、CentOS、Fedora、SUSE、openSUSE。 1、语法ipcs [
2023-06-05

SharedWorker 多页面相互通信示例详解

这篇文章主要为大家介绍了SharedWorker 多页面相互通信示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-08

Go语言基础学习之map的示例详解

哈希表是常见的数据结构,有的语言会将哈希称作字典或者映射,在Go中,哈希就是常见的数据类型map,本文就来聊聊Golang中map的相关知识吧
2023-05-14

Python实现UDP与TCP通信的示例详解

UDP是一种无连接的、不可靠的传输协议;TCP是一种可靠的、面向连接的传输协议。这篇文章主要介绍了Python实现UDP与TCP通信的方法,需要的可以参考一下
2023-03-23

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录