在第一篇里面我们了解了传统IO,这篇我们就来介绍一下Nio吧,废话就不多说了,来看看代码吧
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* NIO服务端
*
* @author -Jimmy_zjf888-
*/
public class NIOServer {
// 通道管理器
private Selector selector;
/**
* 获得一个ServerSocket通道,并对该通道做一些初始化的工作
* @param port绑定的端口号
* @throws IOException
*/
public void initServer(int port) throws IOException {
// 获得一个ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
// 设置通道为非阻塞
serverChannel.configureBlocking(false);
// 将该通道对应的ServerSocket绑定到port端口
serverChannel.socket().bind(new InetSocketAddress(port));
// 获得一个通道管理器
this.selector = Selector.open();
// 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
// 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
/**
* 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
*
* @throws IOException
*/
public void listen() throws IOException {
System.out.println("服务端启动成功!");
// 轮询访问selector
while (true) {
// 当注册的事件到达时,方法返回;否则,该方法会一直阻塞
selector.select();
// 获得selector中选中的项的迭代器,选中的项为注册的事件
Iterator<?> ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 删除已选的key,以防重复处理
ite.remove();
handler(key);
}
}
}
/**
* 处理请求
*
* @param key
* @throws IOException
*/
public void handler(SelectionKey key) throws IOException {
// 客户端请求连接事件
if (key.isAcceptable()) {
handlerAccept(key);
// 获得了可读的事件
} else if (key.isReadable()) {
handelerRead(key);
}
}
/**
* 处理连接请求
*
* @param key
* @throws IOException
*/
public void handlerAccept(SelectionKey key) throws IOException {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
// 获得和客户端连接的通道
SocketChannel channel = server.accept();
// 设置成非阻塞
channel.configureBlocking(false);
// 在这里可以给客户端发送信息哦
System.out.println("新的客户端连接");
// 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
channel.register(this.selector, SelectionKey.OP_READ);
}
/**
* 处理读的事件
*
* @param key
* @throws IOException
*/
public void handelerRead(SelectionKey key) throws IOException {
// 服务器可读取消息:得到事件发生的Socket通道
SocketChannel channel = (SocketChannel) key.channel();
// 创建读取的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = channel.read(buffer);
if(read > 0){
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("服务端收到信息:" + msg);
//回写数据
ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());
channel.write(outBuffer);// 将消息回送给客户端
}else{
System.out.println("客户端关闭");
key.cancel();
}
}
/**
* 启动服务端测试
*
* @throws IOException
*/
public static void main(String[] args) throws IOException {
NIOServer server = new NIOServer();
server.initServer(8888);
server.listen();
}
}
运行上述代码,发现selector.select();这里是一个阻塞点
OK,我们看看能否正常运行吧,做程序就是这样,跑一下测试一下,这里我们测试的代码运行一下也不会怎么样,为了学习嘛
OK,我们看看能否正常运行吧,做程序就是这样,跑一下测试一下,这里我们测试的代码运行一下也不会怎么样,为了学习嘛
学到这里我们总结总结一下吧,传统IO单线程情况下只能有一个客户端,多线程的情况下可以有多个客户端,但非常消耗内存,但NIO就不一样了,他是全能的,一个线程就可以接入多个客户端,为了解释清楚笔者就用如下图片来描述传统IO和NIO的区别吧
如图所示,整个办公室就是我们的系统,ServerSocket就是我们的前台大厅,他监听着端口,
看看有没有客人来,客人我们就理解为socket吧,传统的多线程是不是就是需要多个线程给多个客户端服务啊,要是公司招那么多前台妹子是不是要花一笔不小的开支啊,虽然乐坏了我们这些程序猿了,但对公司来说就是一笔不小的开支,如图所示公司就那么大,人太多都装不下了,连前台妹子都被挤到外面去了( >﹏<。) ,那么介绍完传统IO以后,我们来介绍介绍我们的必杀技NIO吧,如图所示。
如上图所示,整个办公室就是我们的系统,ServerSocketChannel就是我们的前台大厅,他监听着端口,看看有没有客人来,客人我们就理解为socket吧,与传统IO不同的是,咱们公司的妹子(线程池)不需要那么多了,这次我们的前台经过特殊培训,她已经不是一般能力的前台妹子了(神马妹子都升级了?能力惊人的逆天),她比较牛能有同时服务多个客人的能力,同时她还可以监听前台大厅,看看有没有新的客人进来,那么她是怎么欢迎新来的可能呢?
//首先我们先让她知道前台大厅在哪
ServerSocketChannel serverChannel = ServerSocketChannel.open();
// 设置通道为非阻塞的,当然也只能设为非阻塞的,设为true会抛异常的
serverChannel.configureBlocking(false);
// 获得一个通道管理器
this.selector = Selector.open();
// 讲大厅交给一个selector,这个selector我们就想象成一个前台妹子吧,SelectionKey我们就理解为一个标记吧
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
通过上述相信你们应该NIO有所了解了吧,是不是比对着电子书看有意思多了,有意思给个赞把,对了笔者讲讲代码中的几个关键点吧,也是在学习过程中发现的,当然如上代码已经进行bug修复
1.当关闭客户端窗口的时候会报错?为什么会报错
答:那是因为客户端关闭的时候我们还在给它写数据,解决方案:
int read = channel.read(buffer);
if(read > 0){
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("服务端收到信息:" + msg);
//回写数据
ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());
channel.write(outBuffer);// 将消息回送给客户端
}else{
System.out.println("客户端关闭");
key.cancel();
}
2.我们发现selector.select();这里是一个阻塞点,那么为什么说NIO是非阻塞的?
答:这里我们所说的阻塞并不是select阻塞,而是channel.read(buffer)的时候是否阻塞,而传统IO是会阻塞在那里的,当然我们这里的select可以说是阻塞的,也可以说是非阻塞的,为什么这么说呢?其实select也有其他方法
1).selector.select(timeOut);这里有个带毫秒值的方法,当然这里阻塞timeOut毫秒后会返回,只不过返回0而已
2).selector.wakeup();也可以唤醒selector(官方描述:如果当前的select是阻塞的,用.select()或者select(timeOut),这个方法调用后这些方法都会立马返回结果值),当然在后面讲解Netty源码的时候我会讲解该方法,让大家更好的去理解,这里就不多说了。
3.key.OP_WRITE事件神马时候注册呢?
答:其实真正写的时候很少用,其实WRITE主要描述底层缓存区是否有空间,当然正常的时候缓冲区都是存在足够的空间的,如果存在空间就返回true
相关推荐
根据提供的文件信息“netty入门到精通”,我们可以深入探讨Netty框架的相关知识点,包括其基本概念、核心组件、应用场景以及如何逐步掌握这项技术。 ### Netty框架简介 Netty是一款高性能、异步事件驱动的网络应用...
Netty入门教程文档 Netty是Java的网络编程框架,广泛应用于数据采集服务中,本文将对Netty的基本概念和应用进行详细介绍,并将其与ETL技术结合,讲解如何使用Netty进行数据流转和处理。 1. ETL概述 ETL(Extract...
这个“Netty 从入门到精通所有代码”压缩包包含了一系列的示例代码,帮助开发者逐步理解并掌握 Netty 的核心概念和实际应用。 1. **Netty 基本概念** - **NIO (Non-blocking I/O)**:Netty 是基于 Java NIO 构建的...
通过阅读源码,我们可以了解到 Netty 如何实现高效的网络通信,例如它的非阻塞 I/O 模型、事件驱动架构、内存池管理以及编码解码器等核心组件。其中,Channel、EventLoop、ByteBuf 等关键类是理解 Netty 的基础,而 ...
基础篇 走进Java NIO 入门篇 Netty NIO开发指南 中级篇 Netty编解码开发指南 高级篇 Netty多协议开发和应用 源码分析篇 Netty功能介绍和源码分析 架构和行业应用篇 Netty高级特性
《Netty in Action》是一本深入探讨Netty框架的中文指南,它为读者提供了全面了解和熟练使用Netty所需的知识。Netty是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。...
Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和...
《Netty权威指南》是一本深入探讨Netty框架的详细教程,旨在帮助读者全面理解并熟练运用Netty进行高性能网络应用开发。Netty是Java领域的一款开源、异步事件驱动的网络应用程序框架,广泛应用于高性能服务器和客户端...
netty权威指南 PDF电子书下载 带目录书签 完整版,下载
2. **Netty入门**:笔记-3和-5探讨了Netty的入门知识,包括如何搭建基本的Netty服务器和客户端,以及如何扩展Netty来处理HTTP服务。这将帮助初学者快速上手,并理解Netty如何处理网络通信。 3. **核心知识**:笔记-...
【RabbitMQ 入门到精通】:RabbitMQ 是一款流行的消息中间件,它基于 AMQP(Advanced Message Queuing Protocol)协议实现,用于在分布式系统中高效地传输消息,从而实现异步处理、解耦和流量控制。本教程旨在帮助...
内容不仅包含Java NIO入门知识、Netty 的基础功能开发指导、编解码框架定制等,还包括私有协议栈定制和开发、Netty 核心类库源码分析,以及Netty 的架构剖析。 《Netty 权威指南(第2 版)》适合架构师、设计师、...
### Netty开发视频教程知识点详解 #### 一、Netty简介与环境搭建 - **Netty概述**:Netty是一款高性能、异步事件驱动...无论是对于初学者还是有一定基础的开发者来说,这套视频教程都将是入门到精通Netty的最佳选择。
NettyInAction中文版,共13章,从入门到精通。Netty介绍 为什么要使用non-blocking IO(NIO) 阻塞IO(blocking IO)和非阻塞IO(non-blocking IO)对比 Java NIO的问题和在Netty中的解决方案 Netty是基于Java NIO的网络...
- **设置布局**:将按钮和面板添加到了窗口的不同位置上。 - **监听器处理**:通过实现`ActionListener`接口并在`actionPerformed()`方法中处理点击事件,实现了背景色的切换。 #### 示例2: MyPanel 类 - **自定义...
内容不仅包含Java NIO入门知识、Netty 的基础功能开发指导、编解码框架定制等,还包括私有协议栈定制和开发、Netty 核心类库源码分析,以及Netty 的架构剖析。 《Netty 权威指南(第2 版)》适合架构师、设计师、...
8. **最新特性**:第二版可能涵盖了Netty框架的新特性和改进,让读者了解到最新的发展动态。 通过阅读《Netty权威指南 第2版》,开发者不仅可以深入了解Java NIO和Netty框架的工作原理,还能掌握如何有效地利用...
1.Java 并发编程从入门到精通 2.并发编程实战 3.算法 4.高效程序员的45个习惯 5.深入java虚拟机 6.阿里巴巴JAVA开发手册 7.Java核心技术 卷1 基础篇 8.Netty_in_Action 9.java性能优化 10.spring源码解析 11.java 8...