netty入门3 NIO编程

本文介绍了Java NIO编程的基础概念,包括非阻塞IO的特点、缓冲区(buffer)的使用方法及不同类型的缓冲区、通道(channel)的工作原理以及多路复用器(selector)的作用。通过具体的步骤演示了NIO服务端的主要创建流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NIO的简介

在介绍NIO编程之前,我们首先需要澄清一个概念:NIO到底是什么的简介?有人称之为New IO,因为它相对于之前的IO类库是新增的,所以被称为newIO,这是它的官方叫法。但是由于之前老的IO类库是阻塞IO,newIO类库的目标就是要让Java支持非阻塞IO,所以更多的人称之为非阻塞IO(Non-block IO),由于非阻塞IO更能体现NIO的特点,所以本书使用的NIO都指的是非阻塞IO。
与Socket类和ServerSocket类相对应,NIO也提供了SocketChannel 和ServerSocketChannel两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。阻塞模式使用非常简单,但是性能和可靠性都不好,非阻塞模式则正好相反。一般可以根据自己的需要来选择合适的模式,一般来说,低负载、低并发的应用程序可以选择同步阻塞IO以降低编程复杂度,但是对于高负载、高并发的网络应用,需要使用NIO的非阻塞模式进行开发。

缓冲区buffer

首先介绍缓冲区(buffer)的概念,buffer是一个对象,它包含一些要写入或者要读出的数据。在NIO类库中加入Buffer对象,体现了新库与原IO的一个重要区别。在面向流的IO中,可以将数据直接写入或者读入到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类都有完全一样的操作,只是他们所处理的数据类型不一样。因为大多数标准IO操作都使用bytebuffer,所以它除了具有一般缓冲区的操作外还提供了一些特有的操作,方便网络读写。

通道Channel

channel时一个通道,它可以读取和写入数据,就像自来水管一样,网络数据通过channel读取和写入。通道和流的不同支出在于通道时双向的,流只是一个方向上流动,而且通道可以用于读、写或者同时用于读写。
因为channel是全双工的,所以它可以比流更好的映射底层操作系统的API,特别时Unix网络编程模型中,底层操作系统的通道都是全双工。
channel的类图继承结构如下图所示:
channel类继承结构

自顶向下看,前三层主要时Channel接口,用于定义它的功能,后面是一些具体的功能类(抽象类),从类图可以看出channel可以分为两大类:分别时用于网络读写的selectableChannel和用于文件操作的FileChannel.
后面博文里涉及的ServerSocketChannel和SocketChannel都是SelectableChannel的子类。

多路复用器Selector

在这里我们探索多路复用器selector,它是Java NIO编程的基础,数量的掌握selector对于掌握NIO编程至关重要。多路复用器提供选择已经就绪的任务的能力。简单来讲,selector会不断的轮询注册在其上的channel,如果某个channel上面有新的TCP链接接入、读和写时间,这个channel就处于就绪状态,会被selector轮询出来,然后通过selectorkey可以获取就绪CHANNELD的集合。

一个多路复用器selector可以轮询多个channel,由于jdk使用了epoll()代替了传统的select实现,所以它并没有最大连接句柄1024//2048的限制。这也意味者只需要一个线程负责selector的轮询,就可以接入成千上万的客户端。
NIO服务通讯序列图如下:
NIO服务通讯序列图
下面对NIO服务端的主要创建过程进行讲解和说明,作为NIO的入门基础,下面会忽略掉一些在生产环境中部署所需要的一些特性和功能。
步骤一:打开serversocketchannel,用于监听客户端的链接,它是所有客户端链接的父管道,示例代码如下。
ServerSocketChannel acceptorSvr=ServerSocketChannel.open();

步骤二:绑定监听端口,设置连接为非阻塞模式,如下:
acceptor.socket().bind(new InetSocketAddress(InetAddress.getByName(“IP”),port));
acceptor.configureBlocking(false);

步骤三:创建Reactor线程,创建多路复用器并启动线程,如下:
Selector selector=Selector.open();
New Thread(new ReactorTask()).start();

步骤四: 将ServerSocketChannel 注册到Reactor线程的多路复用器selector上,监听ACCEPT事件,如下
SelectionKey key=acceptorSvr.register(selector,SelectionKey.OP_ACCEPT,ioHandler);

步骤五:多路复用器在线程run方法的无线循环体内轮询准备就绪的key,如下
int num=selector.select();
Set selectedKeys=selector.selectorKeys();
Iterator it=selectedKeys.iterator();
while(it.hasNext()){
SelectionKey key=(SelectionKey)it.next();
//…deal with io event…
}

步骤六:多路复用器监听到有新的客户端接入,处理新的接入请求,完成TCP三次握手,建立物理链路,如下:
SocketChannel channel=svrChannel.accept();

步骤七: 设置客户端链路为非阻塞模式,如下:
channel.configureBlocking(false);
channel.socket().setReuseAddress(true);

步骤八:将新接入的客户端连接注册到Reactor线程的多路复用器上,监听读操作,用来读取客户端发来的网路消息。如下:
SelectionKey key=socketChannel.register(selector,SelectionKey.OP_READ,ioHandler);

步骤九: 异步读取客户端请求消息到缓冲区,如下:
int readNumber=channel.read(receivedBuffer);

步骤十:对bytebuffer进行编解码,如果有板报消息指针reset,继续读取后续的报文,将解码成功的消息封装成Task,继续投递到业务线程池中,对业务进行逻辑编排,如下:

Object message=null;
while(buffer.hasRemain()){
	byteBuffer.mark();
	Object message=decode(byteBuffer);
	if(message==null){
	byteBuffer.reset();
	break;
}
	messageList.add(message);
}
if(!byteBuffer.hasRemain()){
	byteBuffer.clear();
}else{
	byteBuffer.compact();
}

if(messageList!=null&&!messageList.isEmpty()){
		for(Object messageE:messageList){
			handlerTask(messageE);
	}
}

步骤十一: 将pojo对象encode成ByteBuf,调用SocketChan的异步write接口,将消息异步发送给客户端,如下:
socketChannel.write(buffer);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值