- 浏览: 52692 次
- 性别:
文章分类
最新评论
IO的处理方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。
java中IO的主要来源是本地和网络传输。
在了解三种处理方式之前,先了解,同步异步,阻塞非阻塞:
1、同步: 用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪; 例如自己亲自去 餐厅吃饭
2、异步: 用户触发IO操作以后,可以干别的事,IO操作完成以后再通知当前线程;例如自己通过美团外卖订购了,送餐上面;自己在等餐到来时间可以干别的事情;
3、阻塞: 当试图进读写文件的时候,发现不可读取或没东西读,则进入等待状态知道可读;例如去楼下排队等餐;
4、非阻塞:用户进程访问数据时,会马上返回一个状态值(可读不可读);例如在餐厅吃饭,先取个号,然后坐着等待服务员报号才能入座吃饭(你可以不停的询问服务员还有多久)。(使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器会通知可读写时再继续进行读写,不断循环直到读写完成)。
一、同步阻塞BIO
在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。
该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,Java中的线程也是比较宝贵的系统资源,线程数量快速膨胀后,系统的性能将急剧下降,随着访问量的继续增大,系统最终就死掉了。不适合高并发和高性能方面。
二、同步非阻塞的NIO
NIO详细文档:http://ifeve.com/java-nio-all/
JDK 1.4中的java.nio.*包中引入新的Java I/O库,其目的是提高速度。实际上,“旧”的I/O包已经使用NIO重新实现过,即使我们不显式的使用NIO编程,也能从中受益。
NIO我们一般认为是New I/O(也是官方的叫法),因为它是相对于老的I/O类库新增的(其实在JDK 1.4中就已经被引入了,但这个名词还会继续用很久,即使它们在现在看来已经是“旧”的了,所以也提示我们在命名时,需要好好考虑),做了很大的改变。但民间跟多人称之为Non-block I/O,即非阻塞I/O,因为这样叫,更能体现它的特点。而下文中的NIO,不是指整个新的I/O库,而是非阻塞I/O。
NIO提供了与传统BIO模型中的Socket和ServerSocket相对应的SocketChannel和ServerSocketChannel两种不同的套接字通道实现。
新增的着两种通道都支持阻塞和非阻塞两种模式。
阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。
对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用NIO的非阻塞模式来开发。
服务端流程图:
客户端流程图:
客户端代码:
服务端代码:
测试代码:
三、异步非阻塞AIO
NIO 2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。
异步的套接字通道时真正的异步非阻塞I/O,对应于UNIX网络编程中的事件驱动I/O(AIO)。他不需要过多的Selector对注册的通道进行轮询即可实现异步读写,从而简化了NIO的编程模型。
客户端代码:
服务端代码:
各种I/O的对比:
BIO、NIO、AIO适用场景分析:
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
另外,I/O属于底层操作,需要操作系统支持,并发也需要操作系统的支持,所以性能方面不同操作系统差异会比较明显。
java中IO的主要来源是本地和网络传输。
在了解三种处理方式之前,先了解,同步异步,阻塞非阻塞:
1、同步: 用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪; 例如自己亲自去 餐厅吃饭
2、异步: 用户触发IO操作以后,可以干别的事,IO操作完成以后再通知当前线程;例如自己通过美团外卖订购了,送餐上面;自己在等餐到来时间可以干别的事情;
3、阻塞: 当试图进读写文件的时候,发现不可读取或没东西读,则进入等待状态知道可读;例如去楼下排队等餐;
4、非阻塞:用户进程访问数据时,会马上返回一个状态值(可读不可读);例如在餐厅吃饭,先取个号,然后坐着等待服务员报号才能入座吃饭(你可以不停的询问服务员还有多久)。(使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器会通知可读写时再继续进行读写,不断循环直到读写完成)。
一、同步阻塞BIO
在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。
该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,Java中的线程也是比较宝贵的系统资源,线程数量快速膨胀后,系统的性能将急剧下降,随着访问量的继续增大,系统最终就死掉了。不适合高并发和高性能方面。
二、同步非阻塞的NIO
NIO详细文档:http://ifeve.com/java-nio-all/
JDK 1.4中的java.nio.*包中引入新的Java I/O库,其目的是提高速度。实际上,“旧”的I/O包已经使用NIO重新实现过,即使我们不显式的使用NIO编程,也能从中受益。
NIO我们一般认为是New I/O(也是官方的叫法),因为它是相对于老的I/O类库新增的(其实在JDK 1.4中就已经被引入了,但这个名词还会继续用很久,即使它们在现在看来已经是“旧”的了,所以也提示我们在命名时,需要好好考虑),做了很大的改变。但民间跟多人称之为Non-block I/O,即非阻塞I/O,因为这样叫,更能体现它的特点。而下文中的NIO,不是指整个新的I/O库,而是非阻塞I/O。
NIO提供了与传统BIO模型中的Socket和ServerSocket相对应的SocketChannel和ServerSocketChannel两种不同的套接字通道实现。
新增的着两种通道都支持阻塞和非阻塞两种模式。
阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。
对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用NIO的非阻塞模式来开发。
服务端流程图:
客户端流程图:
客户端代码:
package com.example.demo.aio; 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.SocketChannel; import java.util.Iterator; import java.util.Set; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/12 * Time: 18:15 * To change this template use File | Settings | File Templates. */ public class NioClient implements Runnable{ private String ip; private int port; private Selector selector; private SocketChannel socketChannel; private volatile boolean started; public NioClient(String ip,int port){ this.ip=ip; this.port=port; try { //创建选择器 selector =Selector.open(); //打开监听端口 socketChannel = SocketChannel.open(new InetSocketAddress(ip,port)); socketChannel.configureBlocking(false);//设置非阻塞模式 started = true; } catch (IOException e) { e.printStackTrace(); System.exit(1); } } public void stop(){ this.started = false; } @Override public void run() { //连接服务器 try { doConnect(); } catch (IOException e) { e.printStackTrace(); System.exit(1); } //循环遍历selector while (started) { try { //无论是否有读写事件发生,selector每隔1s被唤醒一次 selector.select(1000); //阻塞,只有当至少一个注册的事件发生的时候才会继续. // selector.select(); Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> it = keys.iterator(); SelectionKey key = null; while (it.hasNext()) { key = it.next(); it.remove(); try { handleInput(key); } catch (Exception e) { if (key != null) { key.cancel(); if (key.channel() != null) { key.channel().close(); } } } } } catch (Exception e) { e.printStackTrace(); System.exit(1); } } //selector关闭后会自动释放里面管理的资源 if (selector != null) try { selector.close(); } catch (Exception e) { e.printStackTrace(); } } private void handleInput(SelectionKey key) throws IOException { if(key.isValid()){ SocketChannel sc = (SocketChannel) key.channel(); if(key.isConnectable()){ if(sc.finishConnect()); else System.exit(1); } //读消息 if(key.isReadable()){ //创建ByteBuffer,并开辟一个1M的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); //读取请求码流,返回读取到的字节数 int readBytes = sc.read(buffer); //读取到字节,对字节进行编解码 if(readBytes>0){ //将缓冲区当前的limit设置为position=0,用于后续对缓冲区的读取操作 buffer.flip(); //根据缓冲区可读字节数创建字节数组 byte[] bytes = new byte[buffer.remaining()]; //将缓冲区可读字节数组复制到新建的数组中 buffer.get(bytes); String result = new String(bytes,"UTF-8"); System.out.println("客户端收到消息:" + result); } //没有读取到字节 忽略 // else if(readBytes==0); //链路已经关闭,释放资源 else if(readBytes<0){ key.cancel(); sc.close(); } } } } private void doConnect() throws IOException { if(socketChannel.connect(new InetSocketAddress(this.ip,this.port))); else socketChannel.register(selector, SelectionKey.OP_CONNECT); } public void sendMsg(String message) throws IOException { socketChannel.register(selector,SelectionKey.OP_READ); doWrite(socketChannel,message); } //异步发送消息 private void doWrite(SocketChannel channel,String request) throws IOException{ //将消息编码为字节数组 byte[] bytes = request.getBytes(); //根据数组容量创建ByteBuffer ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length); //将字节数组复制到缓冲区 writeBuffer.put(bytes); //flip操作 writeBuffer.flip(); //发送缓冲区的字节数组 channel.write(writeBuffer); //****此处不含处理“写半包”的代码 } }
package com.example.demo.aio; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/13 * Time: 9:13 * To change this template use File | Settings | File Templates. */ public class RunClient { private final static int DEFUALT_PORT=12345; private final static String SERVER_IP="127.0.0.1"; private static NioClient nioClient; public static void start(){ start(DEFUALT_PORT,SERVER_IP); } public synchronized static void start(int port,String ip){ if(nioClient!=null) nioClient.stop(); nioClient = new NioClient(ip,port); new Thread(nioClient,"client").start(); } //向服务器发送消息 public static boolean sendMsg(String msg) throws Exception{ if(msg.equals("q")) return false; nioClient.sendMsg(msg); return true; } public static void main(String[] args){ start(); } }
服务端代码:
package com.example.demo.aio; 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; import java.util.Set; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/12 * Time: 17:42 * To change this template use File | Settings | File Templates. */ public class NioServer implements Runnable { private Selector selector; private ServerSocketChannel serverSocketChannel; private volatile boolean started; public NioServer(int port) throws IOException { //指定选择器 selector = Selector.open(); //打开监听通道 serverSocketChannel = ServerSocketChannel.open(); //设置监听通道是否为阻塞(true)/非阻塞(false) serverSocketChannel.configureBlocking(false); //开启非阻塞模式 //绑定端口, backlog设为1024 serverSocketChannel.socket().bind(new InetSocketAddress(port),1024); //监听客户端连接请求 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //标记服务器开启 started = true; System.out.println("AioServer.AioServer已开启端口:"+port); } public void stop(){ started =false; } @Override public void run() { //如果服务器开启 while(started){ //循环变量selector try { //无论是否有读写事件发生,selector每隔1s被唤醒一次 selector.select(1000); //阻塞,只有当至少一个注册的事件发生的时候才会继续. // selector.select(); Set<SelectionKey> set = selector.selectedKeys(); Iterator<SelectionKey> iterator = set.iterator(); SelectionKey key = null; while(iterator.hasNext()){ key = iterator.next(); iterator.remove();; handleInputSelectionKey(key); } } catch (IOException e) { e.printStackTrace(); } } } public void handleInputSelectionKey(SelectionKey key) throws IOException { if(key.isValid()){ //处理新接入的请求信息 if(key.isAcceptable()){ ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); //通过ServerSocketChannel的accept创建SocketChannel实例 //完成该操作意味着完成TCP三次握手,TCP物理链路正式建立 SocketChannel sc = ssc.accept(); sc.configureBlocking(false);//设置为非阻塞 //注册为读 sc.register(selector, SelectionKey.OP_READ); } //读消息 if(key.isReadable()){ SocketChannel sc = (SocketChannel) key.channel(); //创建ByteBuffer,并开辟一个1M的缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); ////读取请求码流,返回读取到的字节数 int readbytes = sc.read(byteBuffer); //读取到字节,对字节进行编解码 if(readbytes >0){ //将缓冲区当前的limit设置为position=0,用于后续对缓冲区的读取操作 byteBuffer.flip(); //根据缓冲区可读字节数创建字节数组 byte[] bytes = new byte[byteBuffer.remaining()]; //将缓冲区可读字节数组复制到新建的数组中 byteBuffer.get(bytes); String msg = new String(bytes,"UTF-8"); System.out.println("服务器收到消息:" + msg); //发送应答消息 String result = "收到"+msg; doWrite(sc,msg); } //没有读取到字节 忽略 // else if(readBytes==0); //链路已经关闭,释放资源 else if(readbytes<0){ key.cancel(); sc.close(); } } } } //异步发送应答消息 private void doWrite(SocketChannel channel,String response) throws IOException{ //将消息编码为字节数组 byte[] bytes = response.getBytes(); //根据数组容量创建ByteBuffer ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length); //将字节数组复制到缓冲区 writeBuffer.put(bytes); //flip操作 writeBuffer.flip(); //发送缓冲区的字节数组 channel.write(writeBuffer); //****此处不含处理“写半包”的代码 } }
package com.example.demo.aio; import java.io.IOException; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/12 * Time: 18:12 * To change this template use File | Settings | File Templates. */ public class RunServer { private final static int PORT = 12345; private static NioServer nioServer; public static void start(){ start(PORT); } public static synchronized void start(int port){ if(aioServer!=null) nioServer.stop(); try { nioServer = new NioServer(port); } catch (IOException e) { e.printStackTrace(); } new Thread(nioServer,"Server").start(); } public static void main(String[] args){ start(); } }
测试代码:
package com.example.demo.aio; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/13 * Time: 10:07 * To change this template use File | Settings | File Templates. */ public class NioTest { public static void main(String[] args) throws Exception { RunServer.start(); Thread.sleep(1000); RunClient.start(); RunClient.sendMsg("jsjsj"); // while (RunClient.sendMsg(new Scanner(System.in).nextLine())); } }
三、异步非阻塞AIO
NIO 2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。
异步的套接字通道时真正的异步非阻塞I/O,对应于UNIX网络编程中的事件驱动I/O(AIO)。他不需要过多的Selector对注册的通道进行轮询即可实现异步读写,从而简化了NIO的编程模型。
客户端代码:
package com.example.demo.aio; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.CountDownLatch; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/12 * Time: 18:15 * To change this template use File | Settings | File Templates. */ public class AioClient implements CompletionHandler<Void, AioClient>, Runnable{ private String ip; private int port; private AsynchronousSocketChannel asynchronousSocketChannel; private CountDownLatch latch; public AioClient(String ip,int port){ this.ip=ip; this.port=port; try { //创建异步的客户端通道 asynchronousSocketChannel = AsynchronousSocketChannel.open(); } catch (IOException e) { e.printStackTrace(); } } public void run() { //创建CountDownLatch等待 latch = new CountDownLatch(1); //发起异步连接操作,回调参数就是这个类本身,如果连接成功会回调completed方法 asynchronousSocketChannel.connect(new InetSocketAddress(ip, port), this, this); try { latch.await(); } catch (InterruptedException e1) { e1.printStackTrace(); } try { asynchronousSocketChannel.close(); } catch (IOException e) { e.printStackTrace(); } } //连接服务器成功 //意味着TCP三次握手完成 public void completed(Void result, AioClient attachment) { System.out.println("客户端成功连接到服务器..."); } //连接服务器失败 public void failed(Throwable exc, AioClient attachment) { System.err.println("连接服务器失败..."); exc.printStackTrace(); try { asynchronousSocketChannel.close(); latch.countDown(); } catch (IOException e) { e.printStackTrace(); } } //向服务器发送消息 public void sendMsg(String msg){ byte[] req = msg.getBytes(); ByteBuffer writeBuffer = ByteBuffer.allocate(req.length); writeBuffer.put(req); writeBuffer.flip(); //异步写 asynchronousSocketChannel.write(writeBuffer, writeBuffer,new WriteHandler(asynchronousSocketChannel, latch)); } } class WriteHandler implements CompletionHandler<Integer, ByteBuffer> { private AsynchronousSocketChannel clientChannel; private CountDownLatch latch; public WriteHandler(AsynchronousSocketChannel clientChannel,CountDownLatch latch) { this.clientChannel = clientChannel; this.latch = latch; } public void completed(Integer result, ByteBuffer buffer) { //完成全部数据的写入 if (buffer.hasRemaining()) { clientChannel.write(buffer, buffer, this); } else { //读取数据 ByteBuffer readBuffer = ByteBuffer.allocate(1024); clientChannel.read(readBuffer,readBuffer,new ReadClientHandler(clientChannel, latch)); } } public void failed(Throwable exc, ByteBuffer attachment) { System.err.println("数据发送失败..."); try { clientChannel.close(); latch.countDown(); } catch (IOException e) { } } } class ReadClientHandler implements CompletionHandler<Integer, ByteBuffer> { private AsynchronousSocketChannel clientChannel; private CountDownLatch latch; public ReadClientHandler(AsynchronousSocketChannel clientChannel,CountDownLatch latch) { this.clientChannel = clientChannel; this.latch = latch; } @Override public void completed(Integer result,ByteBuffer buffer) { buffer.flip(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); String body; try { body = new String(bytes,"UTF-8"); System.out.println("客户端收到结果:"+ body); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } @Override public void failed(Throwable exc,ByteBuffer attachment) { System.err.println("数据读取失败..."); try { clientChannel.close(); latch.countDown(); } catch (IOException e) { } } }
package com.example.demo.aio; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/13 * Time: 9:13 * To change this template use File | Settings | File Templates. */ public class RunClient { private final static int DEFUALT_PORT=12345; private final static String SERVER_IP="127.0.0.1"; private static AioClient aioClient; public static void start(){ start(DEFUALT_PORT,SERVER_IP); } public synchronized static void start(int port,String ip){ if(aioClient==null){ aioClient = new AioClient(ip,port); new Thread(aioClient,"client").start(); } } //向服务器发送消息 public static boolean sendMsg(String msg) throws Exception{ if(msg.equals("q")) return false; aioClient.sendMsg(msg); return true; } public static void main(String[] args){ start(); } }
服务端代码:
package com.example.demo.aio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.AsynchronousServerSocketChannel; import java.util.concurrent.CountDownLatch; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/12 * Time: 17:42 * To change this template use File | Settings | File Templates. */ public class AioServer implements Runnable { public CountDownLatch latch; public AsynchronousServerSocketChannel asynchronousServerSocketChannel; public AioServer(int port) throws IOException { //创建服务通道 asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(); //绑定端口 asynchronousServerSocketChannel.bind(new InetSocketAddress(port),1024); //标记服务器开启 System.out.println("AioServer.AioServer已开启端口:"+port); } public void run() { //CountDownLatch初始化 //它的作用:在完成一组正在执行的操作之前,允许当前的现场一直阻塞 //此处,让现场在此阻塞,防止服务端执行完成后退出 //也可以使用while(true)+sleep //生成环境就不需要担心这个问题,以为服务端是不会退出的 latch = new CountDownLatch(1); //用于接收客户端的连接 asynchronousServerSocketChannel.accept(this,new AcceptHandler()); try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } package com.example.demo.aio; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/13 * Time: 11:35 * To change this template use File | Settings | File Templates. */ //作为handler接收客户端连接 public class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, AioServer> { public void completed(AsynchronousSocketChannel channel,AioServer aioServer) { //继续接受其他客户端的请求 RunServer.clientCount++; System.out.println("连接的客户端数:" + RunServer.clientCount); aioServer.asynchronousServerSocketChannel.accept(aioServer, this); //创建新的Buffer ByteBuffer buffer = ByteBuffer.allocate(1024); //异步读 第三个参数为接收消息回调的业务Handler channel.read(buffer, buffer, new ReadHandler(channel)); } public void failed(Throwable exc, AioServer aioServer) { exc.printStackTrace(); aioServer.latch.countDown(); } } package com.example.demo.aio; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/13 * Time: 11:42 * To change this template use File | Settings | File Templates. */ public class ReadHandler implements CompletionHandler<Integer, ByteBuffer> { //用于读取半包消息和发送应答 private AsynchronousSocketChannel channel; public ReadHandler(AsynchronousSocketChannel channel) { this.channel = channel; } //读取到消息后的处理 public void completed(Integer result, ByteBuffer attachment) { //flip操作 attachment.flip(); //根据 byte[] message = new byte[attachment.remaining()]; attachment.get(message); try { String expression = new String(message, "UTF-8"); System.out.println("服务器收到消息: " + expression); //向客户端发送消息 doWrite("服务器发送客户端:"+expression); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } //发送消息 private void doWrite(String result) { byte[] bytes = result.getBytes(); ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length); writeBuffer.put(bytes); writeBuffer.flip(); //异步写数据 参数与前面的read一样 channel.write(writeBuffer, writeBuffer,new CompletionHandler<Integer, ByteBuffer>() { public void completed(Integer result, ByteBuffer buffer) { //如果没有发送完,就继续发送直到完成 if (buffer.hasRemaining()) channel.write(buffer, buffer, this); else{ //创建新的Buffer ByteBuffer readBuffer = ByteBuffer.allocate(1024); //异步读 第三个参数为接收消息回调的业务Handler channel.read(readBuffer, readBuffer, new ReadHandler(channel)); } } public void failed(Throwable exc, ByteBuffer attachment) { try { channel.close(); } catch (IOException e) { } } }); } public void failed(Throwable exc, ByteBuffer attachment) { try { this.channel.close(); } catch (IOException e) { e.printStackTrace(); } } }
package com.example.demo.aio; import java.io.IOException; /** * Created with IntelliJ IDEA. * User: 简德群 * Date: 2018/3/12 * Time: 18:12 * To change this template use File | Settings | File Templates. */ public class RunServer { private final static int PORT = 12345; private static AioServer aioServer; public static int clientCount =0; public static void start(){ start(PORT); } public static synchronized void start(int port){ if(aioServer != null){ try { aioServer = new AioServer(port); } catch (IOException e) { e.printStackTrace(); } } new Thread(aioServer,"Server").start(); } public static void main(String[] args){ start(); } }
各种I/O的对比:
BIO、NIO、AIO适用场景分析:
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
另外,I/O属于底层操作,需要操作系统支持,并发也需要操作系统的支持,所以性能方面不同操作系统差异会比较明显。
发表评论
-
java 之sftp实现
2018-03-31 17:41 656上周进行了linux环境下sftp的配置和用户权限的创建:ht ... -
java webService之CXF的使用
2018-03-29 14:25 446使用场景:华为VOD系统与媒资系统的接口,资产数据(元数据XM ... -
java 中jstat的用法
2018-03-20 18:06 715JDK自带VM分析工具jps,jstat,jmap,jcons ... -
javaEE性能优化
2018-03-20 16:41 500性能的优化一般可以从多方面入手,前端资源,java程序,数据传 ... -
jvm gc日志检查
2018-03-20 15:08 367JVM的GC日志的主要参数包括如下几个: -XX:+Pr ... -
负载均衡的几种原理
2018-03-19 16:05 468什么是负载均衡? 就 ... -
基于TCP协议实现RPC
2018-03-19 11:28 711RPC的全称:Remote Process Call,即远程过 ... -
java 多线程
2018-03-16 13:29 350Java 多线程编程 Java 给 ... -
SpringMVC执行流程图
2018-03-15 10:46 466SpringMVC 流程图 DispatcherServle ... -
基于Spring 自定义标签实现
2017-11-30 09:26 549一、源码分析: Spring标签的定义分为默认标签和自定义 ... -
java二维码的生成和解析
2017-09-26 11:15 431一、本文目的: 为了研究对支付宝和微信支付的统一路口管理 ... -
spring-data-redis
2017-09-18 11:54 731Spring-data-redis使用 1、maven依赖 ... -
java,redis
2017-09-18 11:32 355Redis 简介 Redis 是完全开源免费的,遵守BSD协议 ... -
Java xml与实体Bean的转换
2017-09-05 15:24 6971、pom.xml依赖包: <dependenc ... -
Java JVM虚拟机知识要点
2017-08-30 10:25 5941、JVM虚拟机图解: ... -
java 上传小于占用空间为4k的jpg图片异常问题处理
2017-07-19 18:02 525javaWeb上传图片 jpg占用空间为4k时,Commons ... -
Springmvc 注入字符串与时间格式的转换
2017-03-24 11:10 1189以下列出两种spring支持的时间转换 -、方式一 1、 ... -
linux下修改war包
2017-03-06 15:32 1097Linux上修改war包上的文件 www.MyExceptio ... -
itellij idea 11.1.3 mybatis 自动构建代码
2016-11-16 09:50 442步骤一: 1、在工程中pom.xml加添 <buil ... -
intellij idea 下resin容器远程调试
2016-11-16 09:27 5382resin远程调试(我使用的是resin-4.0.41版本): ...
相关推荐
Java作为一门广泛使用的开发语言,提供了多种I/O(Input/Output)通信模型,包括传统的阻塞I/O(BIO)、非阻塞I/O(NIO)以及异步I/O(AIO)。这些通信模型在不同的场景下有着各自的优势,理解和掌握它们对于优化...
为了处理与外部世界的交互,Java提供了三种不同的I/O模型:BIO( Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)。这些模型各有优缺点,适用于不同场景。下面我们将深入探讨这三种I/O模型,并...
Java BIO、NIO、AIO是 Java 中的三种 I/O 模式,每种模式都有其特点和应用场景。下面对每种模式进行详细解释。 Java BIO Java BIO( Blocking I/O)是一种同步阻塞式的 I/O 模式,即服务器实现模式为一个连接一个...
本课程旨在帮助学生全面理解 Java 网络编程中的 BIO、NIO、AIO 三剑客,掌握 RPC 编程的基础知识,并结合实战项目巩固所学。 一、网络编程三剑客 - BIO、NIO、AIO BIO(Blocking I/O)是一种同步阻塞式 I/O 模式,...
对java io总结时编写的测试代码,包括BIO,NIO,AIO的实现,Java io操作是编程人员经常使用到的,以前只是使用没有对这三种IO做系统的了解,本文将对这三种IO作详细的介绍并附有测试完整代码
读书笔记:java网络编程BIONIO, AIO 源码示例
AIO(异步I/O)又称NIO.2,是在Java 7中引入的。AIO的主要特点是,用户线程发起I/O操作后,无需等待,可以继续执行其他任务,等到I/O操作完成时,系统会通过回调或者事件通知用户线程。这种方式使得应用可以更加高效...
总结起来,BIO、NIO、AIO是Java中处理I/O的不同策略,而Netty作为一个强大的网络编程框架,集成了这些策略并提供了更加高级和高效的解决方案。了解这些模型及其在Netty中的实现,对优化网络应用的性能和可扩展性至关...
BIO、NIO 和 AIO 的区别 - **阻塞性**:BIO 是阻塞的,NIO 和 AIO 是非阻塞的。 - **数据流向**:BIO 是面向流的,NIO 是面向缓冲区的,AIO 也是面向缓冲区的。 - **性能**:BIO 由于每个连接都需要一个独立的线程...
Java中BIO、NIO和AIO的区别和应用场景 Java中IO模型有三种:BIO、NIO和AIO,下面我们来详细介绍它们的区别和应用场景。 BIO(Blocking I/O) BIO是Java中最古老的IO模型,它是同步并阻塞的。服务器的实现模式是一...
### 2024年Java常见BIO、NIO、AIO、Netty面试题解析 ...以上内容涵盖了Java中BIO、NIO、AIO以及Netty的相关概念及其区别,有助于深入理解这些技术背后的原理及应用场景。希望对你备战面试有所帮助。
本文将深入探讨Java中的三种IO模型:传统IO(BIO)、非阻塞IO(NIO)以及反应器模式(Reactor),并结合提供的压缩包文件中的示例代码进行解析。 一、传统IO(BIO) 传统的Java IO基于流(Stream)进行数据传输,它...
在Java的发展历程中,IO模型经历了三个主要阶段:BIO(Blocking IO)、NIO(Non-blocking IO)和AIO(Asynchronous IO),这三种模型各自有其特性和适用场景,下面将详细解析它们的工作原理和区别。 **1. BIO(阻塞...
总结来说,这个压缩包提供了一个学习和理解Java中不同I/O模型的起点,尤其是对于希望提升服务器性能或处理高并发场景的开发者来说,深入理解BIO、NIO和AIO的工作原理和使用方法至关重要。通过阅读提供的代码示例,...
"Java中BIO、NIO、AIO的理解" Java中BIO、NIO、AIO的理解是Java高性能IO体系...Java中BIO、NIO、AIO是三个不同的IO模型,它们之间的区别在于同步和异步,阻塞和非阻塞。理解这些概念对于设计高性能的IO体系非常重要。
Java中的I/O(输入/输出)机制是程序与...在Java中,这五种模型分别对应BIO、NIO、AIO、传统的异步I/O(如Java的Future)以及基于回调的异步I/O。这些模型的选择取决于应用场景的需求,如连接数、操作类型和性能要求。
Java编程中的IO模型详解:BIO,NIO,AIO的区别与实际应用场景分析 IO模型在计算机编程中扮演着至关重要的角色,特别是在网络通信中。Java提供了三种主要的IO模型:BIO(Blocking IO),NIO(Non-blocking IO),...
本文将深入探讨Java中的三种主要通讯模型:BIO( Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O),并结合实际的代码示例进行综合演练。 **一、BIO(阻塞I/O)** 1. **概念**:BIO是Java早期的...
读书笔记:Java网络编程BIO、NIO、AIO
Java作为一门广泛使用的编程语言,提供了多种I/O模型来处理数据的读写操作,其中包括BIO(Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)。这些模型各有特点,适用于不同的场景,理解它们的原理...