Netty学习——基础篇2(NIO编程)备份

1 概述

        与Socket类和ServerSocket,NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。阻塞模式使用简单,但性能和可靠性都不好,非阻塞模式则正好相反。一般来说,低负载、地并发的应用程序可以选择同步阻塞I/O降低变成复杂度;对于高负载、高并发的网络应用,需要使用NIO的非阻塞模型进行开发。

2 NIO类库简介

        新的输入/输出(NIO)库是在JDK 1.4中引入的。NIO弥补了原来同步阻塞I/O的不足,它在标准java代码中提供了高速、面向块的I/O。通过定义包含数据的类,以及通过以块的形式处理这些数据,NIO不用使用本机代码就可以利用低级优化,这是原来的I/O无法做到的。

2.1 缓冲区Buffer

        首先介绍缓冲区(Buffer)的概念。Buffer是一个对象,它包含一些要写入或者要读出的数据。在NIO类库中加入Buffer对象,体现了新库与原I/O的一个重要区别。在面向流的I/O中,可以将数据直接写入或者将数据直接读到Stream对象中。

        在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中;在写入数据时,也是写入到缓冲区中。任何使用访问NIO中的数据,都是通过缓冲区进行操作。

        缓冲区实质上是一个数组。通常它是一个字节数组(ByteBuffer),也可以使用其他类型的数据。但是一个缓冲区不仅仅是一个数组,缓冲区提供了对数据的结构化访问以及维护读写位置等信息。

        最常用的缓冲区是ByteBuffer,一个ByteBuffer提供了一组功能用于操作byte数据。除了ByteBuffer,还有其他的一些 缓冲区,实际上,每一种java基本类型(除了boolean类型)都对应有一种缓冲区,具体如下:

        1、ByteBuffer:字节缓冲区

        2、CharBuffer:字符缓冲区

        3、ShortBuffer:短整型缓冲区

        4、IntBuffer:整型缓冲区

        5、LongBuffer:长整型缓冲区

        6、FloatBuffer:浮点型缓冲区

        7、DoubleBuffer:双精度浮点型缓冲区

        缓冲区的类图继承关系如下:

        每一个Buffer类都是Buffer接口的一个子实例。除了ByteBuffer,每一个Buffer类都有完全一样的操作,只是它们所处理的数据类型不一样。因为大多数标准I/O操作都是用ByteBuffer,所以它在具有一般缓冲区的操作之外还提供了一些特有的操作,以方便网络读写。

2.2 通道Channel

        Channel是一个通道,就像自来水管一样,网络数据通过Channel读取和写入。通道与流的不同至于在于通道时双向的,流只是在一个方向上移动(一个流必须是InputStream或OutputStream的子类),而通道可用于读、写或者二者同时进行。

        因为Channel是全双工的,所以它可以比流更好的映射底层操作系统的API。特别是在UNIX网络编程模型中,底层操作系统的通道全都是全双攻的,同时支持读写操作。

        Channel的类图继承关系如下:

 

        自顶向下看,前三层主要是Channel接口,用于定义它的功能,后面是一些具体的功能类(抽象类)。从图中可以看出,实际上Channel分为两大类:用于王立国读写的SelectableChannel和用于文件操作的FileChannel。 

2.3 多路复用器Selector

        多路复用器Selector,它是Java NIO编程的基础,熟练地掌握Selector对于NIO编程至关重要。多路复用器提供选择已经就绪的任务的能力。简单来说,Selector会不断地轮询注册在其上的Channel,如果某个Channel上面发生读写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,记性后续的I/O操作。

        一个多路复用器Selector可以同时轮询多个Channel,由于JDK使用了epoll代替传统的select实现,所以它并没有最大连接句柄1024/2048的限制。这样就意味着只需要一个Selector线程负责Selector的轮询,就可以接入成千上万个客户端。

3 NIO服务端序列图

        NIO服务端通信序列图如下:

        第一步:打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端连接的父管道,示例代码如下:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

         第二步:绑定监听端口,设置连接为非阻塞模型,示例代码如下:

int port = 8080;
serverSocketChannel.socket().bind(new InetSocketAddress(InetAddress.getByName("IP"), port));
serverSocketChannel.configureBlocking(false);

        第三步:创建Reactor线程,创建多路复用器并启动线程,示例代码如下:

//创建Reactor线程
new Thread(new ReactorTask()).start();
//创建多路复用器
Selector selector = Selector.open();

        第四步:将ServerSocketChannel注册到Reactor线程的多路复用器Selector上,监听ACCEPT事件,示例代码如下:

SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT, ioHandler);

        第五步:多路复用器在线程run()方法的无限循环体内轮询准备就绪的key,示例代码如下:

        int num = selector.select();
        Set<SelectionKey> selectededKeys = selector.selectedKeys();
        Iterator<SelectionKey> iterator = selectededKeys.iterator();
        while(iterator.hasNext()){
            SelectionKey key = (SelectionKey) iterator.next();
            //do something
        }

        第六步:多路复用器监听到有新的客户端接入,处理新的接入请求,完成TCP三次握手,建立物理链路,示例代码如下:

SocketChannel channel = serverSocketChannel.accept();

        第七步:设置客户端链路为非阻塞模式,示例代码如下:

        channel.configureBlocking(false);
        channel.socket().setReuseAddress(true);
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

geminigoth

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值