BIO(blocking io)

BIO即为阻塞IO,在网络编程中,它会在建立连接和等待连接的对端准备数据阶段进行阻塞。因此为了支撑高并发的用户访问,一般会为每一个socket 连接分配一个线程。但使用的瓶颈更加明显,无法支持上百万、甚至千万以上的并发。且线程切换带来的开销也更大。

代码示例:

Server端

  1. Server 端绑定 8082 端口
  2. 通过 accept() 方法 阻塞等待客户端建立连接
  3. 当与客户端建立一个 socket 连接通道之后,server 端口将新建一个线程进行 【读】 、【写】

    ( ps: 这里的读是阻塞的,因为当server端发起读的请求时,如果此时对端未准备好数据,那么将一直阻塞等待 。

    直到:1. 对端通过 socket 发送数据2. 将数据从内核态 拷贝到用户态
    )

try {
// 绑定本地 8082 端口
ServerSocket server = new ServerSocket(8082);
while (true) {
//阻塞等待客户端 socket 建立连接
Socket accept = server.accept();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
// 一个线程处理一个socket 连接
BufferedReader reader = null;
PrintWriter out = null;
try {
reader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
String readLine = reader.readLine();
System.out.println("receive message is " + readLine);
out = new PrintWriter(accept.getOutputStream(), true);
out.println("接收完毕,请继续发送!");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (accept != null) {
try {
accept.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}

Client端

  1. 与 server 建立连接的过程,会阻塞

    2.建立连接之后 ,便可通过获取 socket 的 输入、输出流进行读写

    (ps : 与 server 端原因相同,读的时候也会阻塞)
        //阻塞等待连接建立
Socket socket = new Socket("localhost", 8082);
//处理数据
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
out.println("Now establish connection");
System.out.println("从 server 端收到连接信息:" + in.readLine());
} catch (IOException e) {
e.printStackTrace();
} finally {
socket.close();
}

NIO (no blocking io 也叫 new io)

NIO 即非阻塞IO,是JDK 1.4 更新的api, 核心内容是 将建立连接、数据可读、可写等事件交给了操作系统来维护, 通过调用操作系统的 api (如:select、epoll等),来判断当前是否支持:可读、可写,如果当前不可操作,那么直接返回,从而实现了非阻塞。 而不需要像 BIO 那样每次去轮询等待连接的建立以及数据的准备是否完成。主要核心的模块分以下几类:

1. 缓冲区Buffer

一个特定基类(byte、short、int、long 等)的数据容器,用作在建立socket 连接之后的数据传输。

通过 capacity, limit, position,mark 指针来实现数据的读写

get()、put() 方法为每个子类都具有的读、写数据的api方法,当从当前的 position 读或写的同时,position会增加 相应读写的数据的长度。当position 达到limit 之后,再次 get、put则会抛出异常

2. Channel 连接通道

一个 channel 代表一个与“实体”的连接通道,如:硬件设备、文件、网络 socket 。通过连接通道可以使得客户端-服务器互相传输数据,因此通道也是全双工的(因为是建立在TCP 传输层的协议上,因此具备全双工的能力)。

JDK 中 channel 可以分为以下几类:

  • SelectableChannel 用于 阻塞和非阻塞 socket 连接的通道
  • FileChannel 用于文件操作,包括:reading, writing, mapping, and manipulating a file

3.Selector 多路复用选择器

用于 SelectableChannel 的多路复用器,当使用非阻塞的 socket 时,需要将监听的通道 SelectableChannel 感兴趣的事件注册到 selector 多路复用器上(selector 实际上是通过调用操作系统层面的 select、epoll 方法来获取当前可用的时间)

与之对应的感兴趣的事件用 SelectionKey 来表示

  • OP_READ = 1 << 0; 可读
  • OP_WRITE = 1 << 2; 可写
  • OP_CONNECT = 1 << 3; // 完成连接
  • OP_ACCEPT = 1 << 4; // 接收连接

处理流程图:

代码示例:

  1. 通过 ServerSocketChannel 监听 8082 端口
  2. 设置为非阻塞
  3. 选择与操作系统适配的选择器,serverSocketChannel 的 OP_ACCEPT 事件注册到 selector 选择器上
  4. 当OP_ACCEPT 事件触发时,将所有建立好的Socketchannel 连接的感兴趣的事件(这里为 read事件)再次注册到Selector 上
        // 1.根据操作系统选择适当的底层 io复用方法
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8082));
//2.设置为非阻塞
serverSocketChannel.configureBlocking(false);
//3.选择与操作系统适配的选择器
Selector selector = Selector.open();
//将 serverSocket 的OP_ACCEPT 事件注册到 selector 选择器上
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// 4.监听当前连接建立情况
int select = selector.select();
if (select > 0) {
//判断连接业务类型
Set<SelectionKey> set = selector.selectedKeys();
Iterator<SelectionKey> iterator = set.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
//建立连接
if (key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
//通过 accept 方法获取与 server端 已经创建好的 socket连接
SocketChannel sc = ssc.accept();
//设置为非阻塞
sc.configureBlocking(false);
//注册感兴趣的事件为 READ
sc.register(selector, SelectionKey.OP_READ);
}
//可读
else if (key.isReadable()) {
SocketChannel socket = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socket.read(byteBuffer);
System.out.println(new String(byteBuffer.array(), StandardCharsets.UTF_8));
key.interestOps(SelectionKey.OP_WRITE);
}
//可写
else if (key.isWritable()) {
SocketChannel socket = (SocketChannel) key.channel();
socket.write(ByteBuffer.wrap("I'm receive your message".getBytes(StandardCharsets.UTF_8)));
socket.close();
System.out.println("连接关闭成功!");
}
}
}
}

AIO(asynchronous io)

NIO 2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。

    异步的套接字通道时真正的异步非阻塞I/O,对应于UNIX网络编程中的事件驱动I/O(AIO)。他不需要过多的Selector对注册的通道进行轮询即可实现异步读写,从而简化了NIO的编程模型。

代码示例

   private static void server() throws IOException {
//根据操作系统建立对应的底层操作类
AsynchronousServerSocketChannel channel = AsynchronousServerSocketChannel.open();
channel.bind(new InetSocketAddress(8082));
while (true) {
Future<AsynchronousSocketChannel> future = channel.accept();
try {
AsynchronousSocketChannel asc = future.get();
System.out.println("建立连接成功");
Future<Integer> write = asc.write(ByteBuffer.wrap("Now let's exchange datas".getBytes(StandardCharsets.UTF_8)));
while (!write.isDone()) {
TimeUnit.SECONDS.sleep(2);
}
System.out.println("发送数据完成");
asc.close();
} catch (Exception e) {
e.printStackTrace();
}
}
} private static void client() throws Exception {
AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();
Future<Void> future = socketChannel.connect(new InetSocketAddress(8082));
while (!future.isDone()) {
TimeUnit.SECONDS.sleep(2);
}
ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> read = socketChannel.read(buffer);
while (!read.isDone()) {
TimeUnit.SECONDS.sleep(2);
}
System.out.println("接收服务器数据:" + new String(buffer.array(), 0, read.get()));
}

BIO、NIO、AIO 个人总结的更多相关文章

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

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

  2. 拿搬东西来解释udp tcpip bio nio aio aio异步

     [群主]雷欧纳德简单理解 tcpip是有通信确认的面对面通信   有打招呼的过程  有建立通道的过程 有保持通道的确认    有具体传输udp是看到对面的人好像在对面等你 就往对面扔东西[群主]雷欧 ...

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

    关于BIO | NIO | AIO的讨论一直存在,有时候也很容易让人混淆,就我的理解,给出一个解释: BIO | NIO | AIO,本身的描述都是在Java语言的基础上的.而描述IO,我们需要从两个 ...

  4. IO回忆录之怎样过目不忘(BIO/NIO/AIO/Netty)

    有热心的网友加我微信,时不时问我一些技术的或者学习技术的问题.有时候我回微信的时候都是半夜了.但是我很乐意解答他们的问题.因为这些年轻人都是很有上进心的,所以在我心里他们就是很优秀的,我愿意多和努力的 ...

  5. Netty5序章之BIO NIO AIO演变

    Netty5序章之BIO NIO AIO演变 Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠的网络服务器和客户端程序.Netty简化了网络程序的开发,是很多框架和公司都在使 ...

  6. I/O模型系列之三:IO通信模型BIO NIO AIO

    一.传统的BIO 网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请 ...

  7. 【netty】(1)---BIO NIO AIO演变

    BIO NIO AIO演变 Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠的网络服务器和客户端程序.Netty简化了网络程序的开发,是很多框架和公司都在使用的技术. Net ...

  8. Netty序章之BIO NIO AIO演变

    Netty序章之BIO NIO AIO演变 Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠的网络服务器和客户端程序.Netty简化了网络程序的开发,是很多框架和公司都在使用 ...

  9. java BIO/NIO/AIO 学习

    一.了解Unix网络编程5种I/O模型 1.1.阻塞式I/O模型 阻塞I/O(blocking I/O)模型,进程调用recvfrom,其系统调用直到数据报到达且被拷贝到应用进程的缓冲区中或者发生错误 ...

  10. BIO | NIO | AIO (Java版)

    几篇解释的不错的文章: BIO NIO AIO NIO.2 入门,第 1 部分: 异步通道 API 使用异步 I/O 大大提高应用程序的性能

随机推荐

  1. [框架]eclipse搭建ssm框架 一 标签: eclipsetomcat框架 2017-03-25 21:28 1085人阅读 评论(

    虽然现在也做过一些项目,但是自己从头搭起来的框架几乎没有,所以这两天自己搭了一下ssm的框架,下面写一下框架的搭建过程.并且给出增删改查四条线来方便大家熟悉代码. 环境准备 maven3.2.3 ec ...

  2. Libevent:5events相关

    Libevents的基本操作单元是event,每一个event代表了一些条件的集合,这些条件包括: 文件描述符已经准备好读或写 文件描述符正在变为就绪,准备好读或写(仅限于边沿触发) 超时事件 信号发 ...

  3. hdu 2196【树形dp】

    http://acm.hdu.edu.cn/showproblem.php?pid=2196 题意:找出树中每个节点到其它点的最远距离. 题解: 首先这是一棵树,对于节点v来说,它到达其它点的最远距离 ...

  4. Auto CAD 安装问题 “acad.exe - 系统错误 ”

    Auto CAD 安装不上,提示“cad装不上 提示无法启动此程序,因为计算机中丢失 ac1st16.dll” 解决方法: 我的电脑——>右键 属性——>高级选项卡(win7的是高级系统设 ...

  5. 25-3 requests模块的cookie和代理操作

    一.基于requests模块的cookie操作 引言:有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时,如果使用之前requests模块常规操作时,往往达不 ...

  6. React Native声明属性和属性确认

    属性声明 因为用React Native创建的自定义组件可以复用, 我们开发过程中可能一个项目组有多个人同时开发,其他同事可能会用到我们自定义的组件, 但是他们使用的时候很容易忘记使用某些属性,这时候 ...

  7. 15-2 mysql的数据类型

    一.整数类型 整数类型:TINYINT SMALLINT MEDIUMINT INT BIGINT 作用:存储年龄,等级,id,各种号码等 ============================== ...

  8. laravel多表登录出现路由调用错误

    public function auth() { // Authentication Routes... $this->get('login', 'Auth\LoginController@sh ...

  9. Websocket 简单对话:静态网页与pycharm对话

    WebSocket websocket 是一种在单个Tcp连接上进行双全工通信的协议.websocket通信协议于2011年被IETF定为标准RFC6455,并 由RFc7936补充规范.WebSoc ...

  10. 2019-8-31-PowerShell-通过-WMI-获取系统服务

    title author date CreateTime categories PowerShell 通过 WMI 获取系统服务 lindexi 2019-08-31 16:55:58 +0800 2 ...