目录

socket

IO(BIO)和NIO的区别

同步和异步

bio:同步阻塞式IO

NIO:同步非阻塞IO(工作中用的很少)

Buffer使用

NIO代码

AIO


socket

Socket又称“套接字”,应用程序通常通过“套接字”向网络发出请求或者应答请求。

套接字之间的链接过程可以分为四个步骤:服务器监听、客户端请求服务器、服务器确认、客户端确认、进行通信。

IO(BIO)和NIO的区别

其本质就是阻塞和非阻塞的区别。

阻塞概念:应用程序在获取网络数据的时候,如果网络传输数据很慢,那么程序就一直等着,直到传输完毕为止。

非阻塞概念:应用程序直接可以获取已经准备就绪好的数据,无需等待。

IO为同步阻塞形式,NIO为同步非阻塞形式。NIO并没有实现异步,在JDK1.7之后,升级了NIO库包,支持异步非阻塞通信模型即NIO2.0(AIO)。

同步和异步

同步和异步一般是面向操作系统与应用程序对IO操作的层面上来区别的。

同步时,应用程序会直接参与IO读写操作,并且我们的应用程序会直接阻塞到某一个方法上,直到数据准备就绪:或者采用轮询的策略实时监察数据的就绪状态,如果就绪则获取数据。

异步时,则所有的IO读写操作交给操作系统处理,与我们的应用程序没有直接关系,我们程序不需要关心IO读写,当操作系统完成了IO读写操作时,会给我们应用程序发送通知,我们的应用程序直接拿走数据即可。

同步说的是你的server服务器端的执行方式。

阻塞说的是具体的技术,接收数据的方式、状态(IO、NIO)

bio:同步阻塞式IO

//客户端
public class Client {final static String ADDRESS = "127.0.0.1";final static int PORT = 8765;public static void main(String[] args) {Socket socket = null;BufferedReader in = null;PrintWriter out = null;try {socket = new Socket(ADDRESS, PORT);in = new BufferedReader(new  InputStreamReader(socket.getInputStream()));out = new PrintWriter(socket.getOutputStream(),  true);//向服务器端发送数据out.println("接收到客户端的请求数据...");String response = in.readLine();System.out.println("Client: " + response);} catch (Exception e) {e.printStackTrace();} finally {if(in != null){try {in.close();} catch (IOException e) {e.printStackTrace();}}if(out != null){try {out.close();} catch (Exception e) {e.printStackTrace();}}if(socket != null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}socket = null;}}
}//服务器端
public class Server {final static int PROT = 8765;public static void main(String[] args) {ServerSocket server = null;try {server = new ServerSocket(PROT);System.out.println(" server start .. ");//进行阻塞Socket socket = server.accept();//新建一个线程执行客户端的任务new Thread(new ServerHandler(socket)).start();} catch (Exception e) {e.printStackTrace();} finally {if(server != null){try {server.close();} catch (IOException e) {e.printStackTrace();}}server = null;}}
}public class ServerHandler implements Runnable{private Socket socket ;public ServerHandler(Socket socket){this.socket = socket;}@Overridepublic void run() {BufferedReader in = null;PrintWriter out = null;try {in = new BufferedReader(new  InputStreamReader(this.socket.getInputStream()));out = new  PrintWriter(this.socket.getOutputStream(), true);String body = null;while(true){body = in.readLine();if(body == null) break;System.out.println("Server :" + body);out.println("服务器端回送响的应数据.");}} catch (Exception e) {e.printStackTrace();} finally {if(in != null){try {in.close();} catch (IOException e) {e.printStackTrace();}}if(out != null){try {out.close();} catch (Exception e) {e.printStackTrace();}}if(socket != null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}socket = null;}}
}
//(JDK1.5之前没有出NIO的解决办法):BIO+线程池,降低服务器端的压力
{server = new ServerSocket(PORT);System.out.println("server start");Socket socket = null;HandlerExecutorPool executorPool = new  HandlerExecutorPool(50, 1000);//自定义线程池while(true){socket = server.accept();executorPool.execute(new ServerHandler(socket));}
}//自定义线程池
public class HandlerExecutorPool {private ExecutorService executor;public HandlerExecutorPool(int maxPoolSize, int  queueSize){this.executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),maxPoolSize,120L,TimeUnit.SECONDS,new  ArrayBlockingQueue<Runnable>(queueSize));}public void execute(Runnable task){this.executor.execute(task);}
}

NIO:同步非阻塞IO(工作中用的很少)

几个概念:Buffer(缓冲区)、Channel(管道、通道)、Selector(选择器、多路复用器)

NIO的本质就是避免原始的TCP建立连接使用3次握手的操作,减少连接的开销。

Buffer使用

Buffer是一个对象,它包含一些要写入或者要读取的数据。在NIO类库中加入Buffer对象,体现了新库与原IO的一个重要的区别。在面向流的IO中,可以将数据直接写入或读取到Stream对象中。在NIO库中,所有数据都是用缓冲区处理的(读写)。缓冲区实质上是一个数组,通常它是一个字节数组(ByteBuffer),也可以使用其他类型的数据。这个数组为缓冲区提供了数据的访问读写等操作属性,如位置、容量、上限等概念,参考API文档。

Buffer类型:我们最常用的就是ByteBuffer,实际上每一种java基本类型都对应了一种缓冲区(除了Boolean类型)

ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer

/**
各种类型的buffer用法是一样的。
pos(位置)、lim(限制)、cap(容量)
put(x)方法会将该元素放置到当前位置,并且位置+1;但是put(x, x)方法不会改变当前位置。
capacity()获取容量;limit()获取限制,而且是从当前位置开始获取的限制。
get()获取当前位置的数据,并且位置+1。
flip()复位当前位置,并且修改限制为复位之前的位置。最好在put完毕之后flip()一下。
position(0)设置当前位置为0。
remaining()可读数据长度,位置到限制(pos-lim)数量。
*/
// 1 基本操作
//创建指定长度的缓冲区
IntBuffer buf = IntBuffer.allocate(10);
//put还有很多重载方法
buf.put(13);// position位置:0 - > 1
buf.put(21);// position位置:1 - > 2
buf.put(35);// position位置:2 - > 3
//把位置复位为0,也就是position位置:3 - > 0
buf.flip();
System.out.println("使用flip复位:" + buf);//[pos=3 lim=10  cap=10]位置、限制、容量
System.out.println("容量为: " + buf.capacity()); //容量一旦初始化后不允许改变(warp方法包裹数组除外)
System.out.println("限制为: " + buf.limit());         //由于只装载了三个元素,所以可读取或者操作的元素为3 则limit=3
System.out.println("获取下标为1的元素:" + buf.get(1));
System.out.println("get(index)方法,position位置不改变:" + buf);
buf.put(1, 4);//把下标为1的位置赋值4
System.out.println("put(index, change)方法,position位置不变:" +  buf);;
for (int i = 0; i < buf.limit(); i++) {//调用get方法会使其缓冲区位置(position)向后递增一位System.out.print(buf.get() + "\t");
}
System.out.println("buf对象遍历之后为: " + buf);
// 2 wrap方法使用
//  wrap方法会包裹一个数组: 一般这种用法不会先初始化缓存对象的长度,因为没有意义,最后还会被wrap所包裹的数组覆盖掉。
//  并且wrap方法修改缓冲区对象的时候,数组本身也会跟着发生变化。
int[] arr = new int[]{1,2,5};
IntBuffer buf1 = IntBuffer.wrap(arr);//[pos=0 lim=3 cap=3]
System.out.println(buf1);
IntBuffer buf2 = IntBuffer.wrap(arr, 0 , 2);//截取0-2[pos=0  lim=2 cap=3]
//这样使用表示容量为数组arr的长度,但是可操作的元素只有实际进入缓存区的元素长度
System.out.println(buf2);
// 3 其他方法
IntBuffer buf1 = IntBuffer.allocate(10);
int[] arr = new int[]{1,2,5};
buf1.put(arr);
System.out.println(buf1);
//一种复制方法,完全复制
IntBuffer buf3 = buf1.duplicate();
System.out.println(buf3);
//设置buf1的位置属性注意这俩的区别
buf1.position(0);
buf1.flip();
System.out.println(buf1);
System.out.println("可读数据为:" + buf1.remaining());
int[] arr2 = new int[buf1.remaining()];
//将缓冲区数据放入arr2数组中去
buf1.get(arr2);
for(int i : arr2){System.out.print(Integer.toString(i) + ",");
}

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;
public class Server implements Runnable{//1 多路复用器(管理所有的通道)private Selector seletor;//2 建立缓冲区private ByteBuffer readBuf = ByteBuffer.allocate(1024);//3private ByteBuffer writeBuf = ByteBuffer.allocate(1024);public Server(int port){try {//1 打开路复用器this.seletor = Selector.open();//2 打开服务器通道ServerSocketChannel ssc =  ServerSocketChannel.open();//3 设置服务器通道为非阻塞模式ssc.configureBlocking(false);//4 绑定地址ssc.bind(new InetSocketAddress(port));//5 把服务器通道注册到多路复用器上,并且监听阻塞事件ssc.register(this.seletor,  SelectionKey.OP_ACCEPT);System.out.println("Server start, port :" +  port);} catch (IOException e) {e.printStackTrace();}}@Overridepublic void run() {while(true){try {//1 必须要让多路复用器开始监听this.seletor.select();//2 返回多路复用器已经选择的结果集Iterator<SelectionKey> keys =  this.seletor.selectedKeys().iterator();//3 进行遍历while(keys.hasNext()){//4 获取一个选择的元素SelectionKey key = keys.next();//5 直接从容器中移除就可以了keys.remove();//6 如果是有效的if(key.isValid()){//7 如果为阻塞状态if(key.isValid() &&  key.isAcceptable()){this.accept(key);}//8 如果为可读状态if(key.isValid() &&  key.isReadable()){this.read(key);}//9 写数据if(key.isValid() &&  key.isWritable()){//this.write(key); //ssc}}}} catch (IOException e) {e.printStackTrace();}}}private void write(SelectionKey key){//ServerSocketChannel ssc =  (ServerSocketChannel)  key.channel();//ssc.register(this.seletor, SelectionKey.OP_WRITE);}private void read(SelectionKey key) {try {//1 清空缓冲区旧的数据this.readBuf.clear();//2 获取之前注册的socket通道对象SocketChannel sc = (SocketChannel)  key.channel();//3 读取数据int count = sc.read(this.readBuf);//4 如果没有数据if(count == -1){key.channel().close();key.cancel();return;}//5 有数据则进行读取 读取之前需要进行复位方法(把position 和limit进行复位)this.readBuf.flip();//6 根据缓冲区的数据长度创建相应大小的byte数组,接收缓冲区的数据byte[] bytes = new  byte[this.readBuf.remaining()];//7 接收缓冲区数据this.readBuf.get(bytes);//8 打印结果String body = new String(bytes).trim();System.out.println("Server : " + body);// 9..可以写回给客户端数据// 回发数据,并关闭channelsc.configureBlocking(false);//注册到多路复用器上,并设置读取标识sc.register(this.seletor, SelectionKey.OP_READ);ByteBuffer sendBuffer = ByteBuffer.wrap(("我是"  + body).getBytes());sc.write(sendBuffer);//sc.close();} catch (IOException e) {//e.printStackTrace();SocketChannel sc = (SocketChannel)  key.channel();try {System.out.println("关闭连接");key.cancel();  sc.socket().close();  sc.close();} catch (IOException e1) {//e1.printStackTrace();}}}private void accept(SelectionKey key) {try {//1 获取服务通道ServerSocketChannel ssc =  (ServerSocketChannel)  key.channel();//2 执行阻塞方法SocketChannel sc = ssc.accept();//3 设置阻塞模式sc.configureBlocking(false);//4 注册到多路复用器上,并设置读取标识sc.register(this.seletor, SelectionKey.OP_READ);} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {new Thread(new Server(8765)).start();;}
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class Client {//需要一个Selectorpublic static void main(String[] args) {//创建连接的地址InetSocketAddress address = new  InetSocketAddress("127.0.0.1", 8765);//声明连接通道SocketChannel sc = null;//建立缓冲区ByteBuffer buf = ByteBuffer.allocate(1024);try {//打开通道sc = SocketChannel.open();//进行连接sc.connect(address);while(true){//定义一个字节数组,然后使用系统录入功能:byte[] bytes = new byte[1024];System.in.read(bytes);//把数据放到缓冲区中buf.put(bytes);//对缓冲区进行复位buf.flip();//写出数据sc.write(buf);//清空缓冲区数据buf.clear();//从服务端读取消息int readLenth = sc.read(buf);//读取模式buf.flip();byte[] bytesrtn = new byte[readLenth];buf.get(bytesrtn);System.out.println(new String(bytesrtn));buf.clear();}} catch (IOException e) {e.printStackTrace();} finally {if(sc != null){try {sc.close();} catch (IOException e) {e.printStackTrace();}}}}
}

AIO

AIO编程,在NIO基础之上引入了异步通道的概念,并提供了异步文件和异步套接字通道的实现,从而在真正意义上实现了异步非阻塞,NIO只是非阻塞而并非异步。而AIO它不需要通过多路复用器对注册的通道进行轮询操作即可实现异步读写,从而简化了NIO编程模型。也可称之为NIO2.0,这种模式才真正的属于我们异步非阻塞的模型。

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.ExecutionException;
public class Client implements Runnable{private AsynchronousSocketChannel asc ;public Client() throws Exception {asc = AsynchronousSocketChannel.open();}public void connect(){asc.connect(new InetSocketAddress("127.0.0.1",  8765));}public void write(String request){try {asc.write(ByteBuffer.wrap(request.getBytes())).get();//.get()表示异步read();} catch (Exception e) {e.printStackTrace();}}private void read() {ByteBuffer buf = ByteBuffer.allocate(1024);try {asc.read(buf).get();//.get()表示异步buf.flip();byte[] respByte = new byte[buf.remaining()];buf.get(respByte);System.out.println(new  String(respByte,"utf-8").trim());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}}@Overridepublic void run() {while(true){//就是不让它停止}}public static void main(String[] args) throws Exception {Client c1 = new Client();c1.connect();Client c2 = new Client();c2.connect();Client c3 = new Client();c3.connect();new Thread(c1, "c1").start();new Thread(c2, "c2").start();new Thread(c3, "c3").start();Thread.sleep(1000);c1.write("c1 aaa");c2.write("c2 bbbb");c3.write("c3 ccccc");}}
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {//线程池private ExecutorService executorService;//线程组private AsynchronousChannelGroup threadGroup;//服务器通道public AsynchronousServerSocketChannel assc;public Server(int port){try {//创建一个缓存池executorService =  Executors.newCachedThreadPool();//创建线程组threadGroup =  AsynchronousChannelGroup.withCachedThreadPool(executorService,  1);//创建服务器通道assc =  AsynchronousServerSocketChannel.open(threadGroup);//进行绑定assc.bind(new InetSocketAddress(port));System.out.println("server start , port : " +  port);//进行阻塞(其实不是阻塞。)assc.accept(this, new  ServerCompletionHandler());//一直阻塞 不让服务器停止Thread.sleep(Integer.MAX_VALUE);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {Server server = new Server(8765);}
}import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
public class ServerCompletionHandler implements  CompletionHandler<AsynchronousSocketChannel, Server> {@Overridepublic void completed(AsynchronousSocketChannel asc,  Server attachment) {//当有下一个客户端接入的时候 直接调用Server的accept方法,这样反复执行下去,保证多个客户端都可以阻塞attachment.assc.accept(attachment, this);read(asc);}private void read(final AsynchronousSocketChannel asc) {//读取数据ByteBuffer buf = ByteBuffer.allocate(1024);asc.read(buf, buf, new CompletionHandler<Integer,  ByteBuffer>() {@Overridepublic void completed(Integer resultSize,  ByteBuffer attachment) {//进行读取之后,重置标识位attachment.flip();//获得读取的字节数System.out.println("Server -> " + "收到客户端的数据长度为:" + resultSize);//获取读取的数据String resultData = new  String(attachment.array()).trim();System.out.println("Server -> " + "收到客户端的数据信息为:" + resultData);String response = "服务器响应, 收到了客户端发来的数据: " + resultData;write(asc, response);}@Overridepublic void failed(Throwable exc, ByteBuffer  attachment) {exc.printStackTrace();}});}private void write(AsynchronousSocketChannel asc, String  response) {try {ByteBuffer buf = ByteBuffer.allocate(1024);buf.put(response.getBytes());buf.flip();asc.write(buf).get();//.get()表示异步} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}@Overridepublic void failed(Throwable exc, Server attachment) {exc.printStackTrace();}
}

谈谈java的bio、nio、aio模型相关推荐

  1. JAVA IO : BIO NIO AIO

    JAVA IO : BIO NIO AIO 同步异步.阻塞非阻塞概念 同步与异步 阻塞与非阻塞 IO VS NIO VS AIO 面向流与面向缓冲 阻塞与非阻塞IO BIO.NIO.AIO的JAVA实 ...

  2. Java IO(BIO, NIO, AIO) 总结

    文章转载自:JavaGuide 目录 BIO,NIO,AIO 总结 同步与异步 阻塞和非阻塞 1. BIO (Blocking I/O) 1.1 传统 BIO 1.2 伪异步 IO 1.3 代码示例 ...

  3. IO之 java中BIO NIO AIO原理、区别以及应用

    在本篇文章中,我们主要介绍一下java中的BIO NIO AIO,重点是NIO 先说一下同步.异步.阻塞和非阻塞. 简单来讲,同步和异步是针对内核和应用程序之间的交互而言的:阻塞和非阻塞其实是针对进程 ...

  4. Java中BIO,NIO,AIO

    这里建议不太清楚这个三个概念的可以看我的这篇文章,通俗易懂http://blog.csdn.net/sky_100/article/details/77603576 一.BIO 在JDK1.4出来之前 ...

  5. JAVA 中BIO,NIO,AIO的理解

    [转自]http://qindongliang.iteye.com/blog/2018539 在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 序号 问题 1 什么是同步? ...

  6. Java之BIO NIO AIO区别联系

    1F 说一说I/O 首先来说一下什么是I/O? 在计算机系统中I/O就是输入(Input)和输出(Output)的意思,针对不同的操作对象,可以划分为磁盘I/O模型,网络I/O模型,内存映射I/O, ...

  7. Java中BIO,NIO,AIO的理解

    在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 1 什么是同步?  2 什么是异步?  3 什么是阻塞?  4 什么是非阻塞?  5 什么是同步阻塞?  6 什么是同步非 ...

  8. java io bio nio aio 详解

    BIO.NIO.AIO的区别: BIO就是基于Thread per Request的传统server/client实现模式, NIO通常采用Reactor模式, AIO通常采用Proactor模式, ...

  9. bio阻塞的缺点_java 中的 BIO/NIO/AIO 详解

    java 的 IO 演进之路 我们在前面学习了 linux 的 5 种 I/O 模型详解 下面我们一起来学习下如何使用 java 实现 BIO/NIO/AIO 这 3 种不同的网络 IO 模型编程. ...

  10. 也谈BIO | NIO | AIO (Java版--转)

    http://my.oschina.net/bluesky0leon/blog/132361 关于BIO | NIO | AIO的讨论一直存在,有时候也很容易让人混淆,就我的理解,给出一个解释: BI ...

最新文章

  1. Javascript 取小数点后面N位
  2. 辅助驾驶等级_自动驾驶分为几级?我们离真正的自动驾驶还有多远?
  3. 成功解决lib\subprocess.py, line 997, in _execute_child startupinfo) FileNotFoundError: [WinError 2]
  4. linux算法平台,Linux实时调度算法与测试平台的研究与实现
  5. Java常见面试知识点:继承、接口、多态、代码块
  6. django与mysql实现增删_django与mysql实现简单的增删查改
  7. WordPress主题 酱茄模块源码
  8. for for..in语句的基本结构 常用的内置对象和内置放法
  9. 完整的Socket代码
  10. Hadoop-RPC底层实现与解析
  11. Java clone() 浅拷贝 深拷贝
  12. 运营人员消消气,这个工具让数据分析轻松驾驭
  13. 计算机毕业设计(附源码)python疫情防控管理系统
  14. AR入门之动画的制作与导入
  15. html怎么去除em的倾斜,HTML5 :b/strong加粗,i/em倾斜区别
  16. 最新发布!2018年区块链数字货币项目最赚钱方法排行榜
  17. echarts关系图指向混乱
  18. Linux - cannot update mailbox /var/mail/root for user root. error writing messa ge: File too large
  19. Linux端的qbittorrent目录,qBittorrent v4.3.0.10便携增强版-BT/磁力下载软件
  20. 转自栖息谷论坛-30岁之前成功12条黄金法则

热门文章

  1. 关于日志的常用配置(log4j和logback)
  2. html页面渲染vue组件,Vue组件页面渲染的基本流程
  3. iservice list方法_MyBatis-Plus 通用IService使用详解
  4. 计算机计算各科及格率,某两个班数学考试成绩如下,要求计算分析指标,用..._投资分析考试_帮考网...
  5. websocket 代理tcp_netty实现websocket请求实战
  6. 树结构之树和二叉树的概念以及如何用面向对象思想进行结构定义01
  7. c语言理解参数,c语言中对可变参数列表的简单理解
  8. java底层原理书籍_不愧是阿里p8大佬!终于把Java 虚拟机底层原理讲清楚了,请签收...
  9. nebula加入时间约束条件,查询结果没有输出
  10. python中的urllib库_七、urllib库(一)