一、BIO
1、机制
采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的链接,它接收到客户端的连接请求之后为每个客户端请求创建一个新的线程进行链路处理,处理完成之后通过输出流将响应返回给客户端,线程销毁,这就是典型的一请求一应答的通信模型。
2、分析
当客户端并发访问量增加后,服务端的线程个数和客户端并发访问按1:1的正比关系递增,线程膨胀之后,系统的性能会急剧下降,甚至会发生线程堆栈溢出、创建失败,最终发生宕机或将死的惨状。
当然我们可以在服务端使用线程池的方式,来保护我们的系统受到高并发的冲击,但是即使线程池在大毕竟也是有限的,这样会出现大量的请求等待线程池的资源,从而性能、时延、并发量还是会面临很糟糕的情况。
二、NIO
1、机制
概念组成就不说了,网上很多。
采用nio通信模型的服务端,通常由一个独立的线程selector(选择器)来管理一个或多个channel,当channel注册了selector之后,selector会监听channel的各种事件,如SelectionKey.OP_ACCEPT-接收事件,当注册的事件发生后,通过迭代器获取选中的事件-SelectionKey,如果SelectionKey为请求连接事件,则保存客户端的SocketChannel并设置非阻塞,再添加可读监听事件,这样在数据可读之前,selector可以做一些其他的事情;如果SelectionKey为可读事件,则可以通过线程池用SocketChannel获取数据,进行接下来的逻辑处理,最后将响应返回给客户端。
2、分析
由于selector可以判断数据的接收状态,所以可以节省掉等待io数据的时间,而监听状态的时间会很快,可以由单线程完成,这样也避免了线程的上下文切换。
三、代码
1、服务端
public class NIOServer { //选择器 private Selector selector; /** * 对该通道做一些初始化的工作 */ public void initServer(int port) throws IOException { // 获得ServerSocket通道 ServerSocketChannel serverChannel = ServerSocketChannel.open(); // 设置通道为非阻塞 serverChannel.configureBlocking(false); // 绑定到port端口 serverChannel.socket().bind(new InetSocketAddress(port)); // 获得选择器 this.selector = Selector.open(); //为该通道注册SelectionKey.OP_ACCEPT事件 serverChannel.register(selector, SelectionKey.OP_ACCEPT); } /** * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理 */ @SuppressWarnings("unchecked") public void listen() throws IOException { // 轮询访问selector while (true) { //当注册的事件到达时,方法返回;否则,该方法会一直阻塞 selector.select(); // 获得selector中选中的项的迭代器,选中的项为注册的事件 Iterator ite = this.selector.selectedKeys().iterator(); while (ite.hasNext()) { SelectionKey key = (SelectionKey) ite.next(); // 删除已选的key,以防重复处理 ite.remove(); // 客户端请求连接事件 if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key .channel(); // 获得和客户端连接的通道 SocketChannel channel = server.accept(); // 设置成非阻塞 channel.configureBlocking(false); //可以给客户端发送信息 channel.write(ByteBuffer.wrap(new String("abc").getBytes())); //在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。 channel.register(this.selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 获得了可读的事件 read(key); } } } } /** * 处理逻辑 */ public void read(SelectionKey key) throws IOException{ // 服务器可读取消息:得到事件发生的Socket通道 SocketChannel channel = (SocketChannel) key.channel(); // 创建读取的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(10); channel.read(buffer); byte[] data = buffer.array(); String msg = new String(data).trim(); System.out.println("服务端收到信息:"+msg); ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes()); channel.write(outBuffer);// 将消息回送给客户端 } /** * 启动服务端测试 */ public static void main(String[] args) throws IOException { NIOServer server = new NIOServer(); server.initServer(8000); server.listen(); } }
2、客户端
public class NIOClient { //选择器 private Selector selector; /** * 对该通道做一些初始化的工作 */ public void initClient(String ip,int port) throws IOException { // 获得一个Socket通道 SocketChannel channel = SocketChannel.open(); // 设置通道为非阻塞 channel.configureBlocking(false); // 选择器 this.selector = Selector.open(); // 客户端连接服务器,其实方法执行并没有实现连接,需要在listen()方法中调 //用channel.finishConnect();才能完成连接 channel.connect(new InetSocketAddress(ip,port)); //将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_CONNECT事件。 channel.register(selector, SelectionKey.OP_CONNECT); } /** * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理 */ @SuppressWarnings("unchecked") public void listen() throws IOException { // 轮询访问selector while (true) { selector.select(); // 获得selector中选中的项的迭代器 Iterator ite = this.selector.selectedKeys().iterator(); while (ite.hasNext()) { SelectionKey key = (SelectionKey) ite.next(); // 删除已选的key,以防重复处理 ite.remove(); // 连接事件发生 if (key.isConnectable()) { SocketChannel channel = (SocketChannel) key .channel(); // 如果正在连接,则完成连接 if(channel.isConnectionPending()){ channel.finishConnect(); } // 设置成非阻塞 channel.configureBlocking(false); //在这里可以给服务端发送信息哦 channel.write(ByteBuffer.wrap(new String("abc").getBytes())); //在和服务端连接成功之后,为了可以接收到服务端的信息,需要给通道设置读的权限。 channel.register(this.selector, SelectionKey.OP_READ); // 获得了可读的事件 } else if (key.isReadable()) { read(key); } } } } /** * 处理逻辑 */ public void read(SelectionKey key) throws IOException{ SocketChannel channel = (SocketChannel) key.channel(); // 创建读取的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(10); channel.read(buffer); byte[] data = buffer.array(); String msg = new String(data).trim(); System.out.println("客户端收到信息:"+msg); } /** * 启动客户端测试 */ public static void main(String[] args) throws IOException { NIOClient client = new NIOClient(); client.initClient("localhost",8000); client.listen(); } }
相关推荐
"Java使用BIO和NIO进行文件操作对比代码示例" Java BIO和NIO是两种不同的输入/输出(IO)模型,在文件操作中发挥着重要作用。BIO(Blocking I/O)是一种同步阻塞IO模式,而NIO(Non-Blocking I/O)是一种同步非阻塞...
压缩包内的`demo2_onlyBufferStream.txt`和`demo3_onlyBufferStream.txt`分别展示了BIO与NIO使用缓冲区进行IO操作的差异,通过对比可以更好地理解两者的性能和效率区别。 总结,Java IO的发展经历了从BIO到NIO的...
为了处理与外部世界的交互,Java提供了三种不同的I/O模型:BIO( Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)。这些模型各有优缺点,适用于不同场景。下面我们将深入探讨这三种I/O模型,并...
在Java编程领域,I/O(Input/Output)技术是至关重要的,它关乎到程序与外部世界的交互效率。这里我们主要探讨三种不同的I/O模型:BIO( Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)。这三种...
**对比与选择:** - **BIO**:适合于连接数量较少且对响应时间要求不高的场景,如简单的文件操作或短连接服务。 - **NIO**:适合于需要处理大量并发连接,且对响应时间有一定要求的服务器,如Web服务器、聊天服务器...
1. **BIO、NIO、AIO的区别和应用场景**:对比它们的工作原理、性能特点和适用场景。 2. **NIO的Selector机制**:解释选择器如何工作,如何注册和监听通道,以及选择器的选择操作。 3. **Netty的Channel和Buffer**:...
本篇文章将深入探讨三种主要的Java IO模型:BIO( Blocking IO)、NIO(Non-Blocking IO)和AIO(Asynchronous IO),并以代码实例解析它们的工作原理和优缺点。 首先,我们来看BIO,即同步阻塞IO模型。在BIO中,每...
**BIO与NIO的对比:** 1. **效率**:NIO的非阻塞特性使得它在处理高并发连接时更有效率,因为线程不会被无谓地阻塞。 2. **资源消耗**:BIO需要为每个连接创建线程,而NIO只需一个或少数几个线程就能管理所有连接。 ...
3. 非阻塞I/O:对比NIO和BIO,解释非阻塞I/O的优势,并展示如何在实际项目中应用。 4. 多路复用:详述选择器的工作原理,如何注册、选择和处理事件,以及如何优化多路复用的性能。 5. 客户端与服务器通信:介绍如何...
本文将通过一个对比实例,探讨一般Socket客户端与Mina NIO (Non-blocking I/O) Socket客户端的差异和特点,帮助开发者理解这两种技术在实际应用中的选择。 首先,普通Socket客户端基于BIO(Blocking I/O)模型,它...
10. **NIO与BIO的比较**:对比两种I/O模型的优缺点,帮助读者理解何时选择NIO,何时使用传统的BIO。 通过阅读这份Java NIO PDF书籍,读者将能够掌握NIO的基本原理,了解其在系统设计中的作用,并学会如何利用NIO...
3. BIO与NIO对比 - **面向流与面向缓冲**:BIO是以流的方式处理数据,每次从流中读取,无法前后移动数据;NIO则是面向缓冲区,数据读取到缓冲区,可灵活处理。 - **阻塞与非阻塞**:BIO的IO操作是阻塞的,线程会被...
Java提供了多种IO方式,包括传统的阻塞IO(BIO)、非阻塞IO(NIO)以及异步非阻塞IO(AIO,也称为NIO 2)。 1. **传统阻塞IO(BIO)**: - 基于`java.io`包,主要使用`File`、`InputStream`、`OutputStream`、`...
与 Exception 有关的 Java 关键字 throws 和 throw try 、finally 、catch 什么是 Error 内部类 创建内部类集合 Iterable 接口顶层接口 ArrayList Vector LinkedList 类Stack HashSet TreeSet LinkedHashSet 类 ...
5. **NIO与BIO对比**:分析两者在性能、线程模型、适用场景上的差异,理解何时选择NIO。 6. **NIO的实际应用**:例如在高并发网络服务器、大文件传输、多线程通信等场景中的应用。 通过扫地僧多隆的讲解,开发者...
- **示例项目**:项目中可能包含一个名为"javaBIO_Socket"的子目录,展示了如何使用Java BIO实现Socket服务器和客户端的基本通信流程。 2. **Java NIO (Non-blocking I/O)** - **概念**:NIO引入了选择器...
1. BIO、NIO、AIO的区别:BIO是阻塞式IO,NIO是非阻塞式IO,AIO是异步IO。 2. Files的常用方法:Files类提供了许多文件操作方法。 反射机制 1. 反射机制的优缺点:反射机制可以动态地调用类和方法,但也可能会...
Java基本功:Java入门:涵盖了Java语言的特点、JVM、JDK、JRE的详细解释,Oracle JDK与OpenJDK的对比,Java和C++的区别,以及Java程序的主类定义等。基本数据类型:详细介绍了Java中的基本数据类型及其包装类,...
通过对比BIO、NIO和AIO的不同特点,可以根据实际应用场景选择最适合的技术方案。此外,深入理解Buffer、Channel和Selector的工作原理,有助于更好地利用Java NIO的强大功能,构建高性能的应用系统。
9. **对比优化**:通常会将NIO的性能与BIO或AIO(Asynchronous I/O)进行比较,以确定哪种模型更适合特定的场景和需求。 10. **系统配置**:硬件配置、操作系统设置、JVM参数等都会影响NIO的性能,测试应考虑这些...