Java IO,BIO、NIO、AIO

article/2025/9/11 1:05:15

操作系统中的 I/O
      以上是 Java 对操作系统的各种 IO 模型的封装,【文件的输入、输出】在文件处理时,其实依赖操作系统层面的 IO 操作实现的。【把磁盘的数据读到内存种】操作系统中的 IO 有 5 种:
阻塞、
非阻塞、【轮询】
异步、
IO复用、【多个进程的 IO 注册到管道上】
信号驱动 IO
 

1.传统的IO流会进行阻塞操作、一个字节一个字节操作
2.NIO提供了一个区域块的 数据映射、 异步的IO流操作
3.通道是 用于获取流中数据 ===>【channel获取的是传统IO流中的数据,读写】
4.缓冲区是 用于保存通道中的数据- ===>【buffer获取的是channel中的数据,读写】

 传统IO操作请看IO操作
IO和NIO的区别
IO:1.面向流(Stream) 2.阻塞IO(Blocking IO)
NIO:1.面向缓冲区 2.非阻塞IO(NO Blocking IO)3. 选择器(Selectors)

(一)引言
IO流是Java中比较难理解的一个知识点,但是IO流在实际的开发场景中经常会使用到,比如Dubbo底层就是NIO进行通讯。本文将介绍Java发展过程中出现的三种IO:BIO、NIO以及AIO,重点介绍NIO。

(二)什么是BIO
BIO即同步阻塞IO,实现模型为一个连接就需要一个线程去处理。这种方式简单来说就是当有客户端来请求服务器时,服务器就会开启一个线程去处理这个请求,即使这个请求不干任何事情,这个线程都一直处于阻塞状态。

BIO模型有很多缺点,最大的缺点就是资源的浪费。想象一下如果QQ使用BIO模型,当有一个人上线时就需要一个线程,即使这个人不聊天,这个线程也一直被占用,那再多的服务器资源都不管用。

同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。
异步: 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者并没有返回结果,此时可以处理其他的请求,被调用者通常依靠事件,回调等机制来通知调用者其返回结果。
同步和异步的区别最大在于 异步调用者不需要等待处理结果,被调用者会通过回调等机制来通知调用者其返回结果。
阻塞: 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
非阻塞: 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。
 

 BIO (Blocking I/O) 同步阻塞
     服务端创建一个 ServerSocket , 然后就是客户端用一个Socket 去连接服务端的那个 ServerSocket, ServerSocket 接收到了一个的连接请求就创建一个Socket和一个线程去跟那个 Socket 进行通讯。接着客户端和服务端就进行阻塞式的通信,客户端发送一个请求,服务端 Socket 进行处理后返回响应,在响应返回前,客户端那边就阻塞等待,什么事情也做不了。
     这种方式的缺点, 每次一个客户端接入,都需要在服务端创建一个线程来服务这个客户端,这样大量客户端来的时候,就会造成服务端的线程数量可能达到了几千甚至几万,这样就可能会造成服务端过载过高,最后崩溃死掉。

(三)BIO代码实践

我们通过socket模拟BIO的实现逻辑

首先建立Server,建立一个ServerSocket对象,绑定端口,然后等待连接,如果连接成功就新建一个线程去处理连接。

server服务端:两种情况:

1.单线程处理多个客户端,没处理一个客户端的时候其他客户端要等待

2.多线程处理多个客户端 ,也就是服务端接受到客户端的socket就开启一个线程去处理.

package com.cn.jettech.jettoproimage.controller.imagecontroller01.imagecontroller01.io.bio;import java.io.IOException;
import java.net.*;/*** BIO即同步阻塞IO,实现模型为一个连接就需要一个线程去处理***/
public class BIOServer {private static Socket socket = null;private static int thread_queue_size = 100;private static volatile int i = 0;private static int server_port = 8080;private static String server_ip = "192.168.0.17";public static void main(String[] args) throws  Exception{//ServerSocket serverSocket = new ServerSocket(BIOServer.server_port,BIOServer.thread_queue_size,InetAddress.getByName(BIOServer.server_ip));ServerSocket serverSocket = new ServerSocket();//该选项用来决定如果网络上仍然有数据向旧的ServerSocket传输数据,是否允许新的ServerSocket绑定到与旧的ServerSocket同样的端口上,//该选项的默认值与操作系统有关,在某些操作系统中,允许重用端口,而在某些系统中不允许重用端口。//当ServerSocket关闭时,如果网络上还有发送到这个serversocket上的数据,这个ServerSocket不会立即释放本地端口,//而是等待一段时间,确保接收到了网络上发送过来的延迟数据,然后再释放端口。//值得注意的是,public void setReuseAddress(boolean on) throws SocketException必须在ServerSocket还没有绑定到一个本地端口之前使用,//否则执行该方法无效。此外,两个公用同一个端口的进程必须都调用serverSocket.setReuseAddress(true)方法,才能使得一个进程关闭ServerSocket之后,//另一个进程的ServerSocket还能够立刻重用相同的端口。//serverSocket.setReuseAddress(true);//SO_RCVBUF 表示 Socket 的用于输入数据的缓冲区的大小. 一般说来, 传输大的连续的数据块(基于HTTP 或 FTP 协议的通信) 可以使用较大的缓冲区,//这可以减少传输数据的次数, 提高传输数据的效率. 而对于交互频繁且单次传送数据量比较小的通信方式(Telnet 和 网络游戏), 则应该采用小的缓冲区,//确保小批量的数据能及时发送给对方. 这种设定缓冲区大小的原则也同样适用于 Socket 的 SO_SNDBUF 选项.//serverSocket.setReceiveBufferSize(10000);//SO_TIMEOUT表示ServerSocket的accept()方法等待客户连接的超时时间,以毫秒为单位。如果SO_TIMEOUT的值为0,表示永远不会超时,这是SO_TIMEOUT的默认值。//当服务器执行ServerSocket的accept()方法时,如果连接请求队列为空,服务器就会一直等待,直到接收到了客户连接才从accept()方法返回。如果设定了超时时间,//那么当服务器等待的时间超过了超时时间,就会抛出SocketTimeoutException,它是InterruptedException的子类。//当底层的Socket实现不支持SO_TIMEOUT选项时,这两个方法将抛出SocketException例外。不能将timeout设为负数,//否则setSoTimeout方法将抛出IllegalArgumentException例外。//serverSocket.setSoTimeout(10000);//backlog : 输入连接指示(对连接的请求)的最大队列长度被设置为 backlog 参数。如果队列满时收到连接指示,则拒绝该连接。//1. backlog参数必须是大于 0 的正值。如果传递的值等于或小于 0,则假定为默认值。//2. 经过测试这个队列是按照FIFO(先进先出)的原则。//3. 如果将accept这个函数放在一个循环体中时,backlog参数也不会有什么作用。或者简单的讲运行ServerSocket的这个线程会阻塞时,无论是在accept,还是在read处阻塞,这个backlog参数才生效。serverSocket.bind(new InetSocketAddress(BIOServer.server_port),BIOServer.thread_queue_size);
//        System.out.println(serverSocket.isBound() && !serverSocket.isClosed());
//        if(serverSocket.isBound()) {
//            System.out.println(serverSocket.getLocalPort());
//            System.out.println(serverSocket.getInetAddress().getHostAddress());
//        }while (true) {//等待连接  阻塞++i;System.out.println("等待客户端的连接");socket = serverSocket.accept();System.out.println("服务端已经获取到了客户端你的第"+i+"个socket,连接成功"+socket.getRemoteSocketAddress());try {Thread.sleep(1000); //thread_queue_size参数是模拟请求的队列池子大小---单线程模式下,这样客户端请求过大服务器不予处理。} catch (InterruptedException e) {throw new RuntimeException(e);}//System.in.read();//Thread thread= new Thread(new MyRun(socket));  //多线程处理客户端//thread.start();}}
}
class MyRun implements  Runnable {private Socket socket;public MyRun(Socket socket) {this.socket = socket;}public MyRun() {}public void run() {byte[] bytes=new byte[33];try {System.out.println("服务端等待读数据");int length=socket.getInputStream().read(bytes);System.out.println("读到客户端传过来的数据的长度是:" +length);
//            System.out.println("服务端每次处理的最大数据是:" +bytes.length);
//            System.out.println("============第一段"+new String(bytes,0,6)+"=============");System.out.println("======"+Thread.currentThread().getName()+"======读取整体"+new String(bytes,0,length)+"=============");} catch (IOException e) {e.printStackTrace();}finally {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}
}

client客户端:属于真正的客户端,因为数多线程模拟的客户端

package com.cn.jettech.jettoproimage.controller.imagecontroller01.imagecontroller01.io.bio;
import java.io.IOException;
import java.net.Socket;
public class BIOClient {private static int socket_size = 100;private static int server_port = 8080;private static String server_ip = "192.168.0.17";public static void main(String[] args) throws Exception{Socket[] client = new Socket[BIOClient.socket_size];for (int i = 0; i < BIOClient.socket_size; i++) {final int index = i;new Thread(()->{try {client[index] = new Socket(BIOClient.server_ip,BIOClient.server_port);
//                    client[index].getOutputStream().write("我是第".getBytes());
//                    client[index].getOutputStream().write(index);
//                    client[index].getOutputStream().write("客户端过来的数据".getBytes());System.out.println("第 " + (index+1) + "客户端连接成功");} catch (IOException e) {throw new RuntimeException(e);}},String.valueOf(i)).start();}}
}

BIO是阻塞的,如果没有多线程,BIO就需要一直占用CPU,而NIO则是非阻塞IO,NIO在获取连接或者请求时,即使没有取得连接和数据,也不会阻塞程序。NIO的服务器实现模式为一个线程可以处理多个请求(连接)。也就是说BIO服务端多线程也可以处理多个客户端,但是这样服务端线程数量会增多性能会下降。

(四)什么是NIO
BIO是阻塞的,如果没有多线程,BIO就需要一直占用CPU,而NIO则是非阻塞IO,NIO在获取连接或者请求时,即使没有取得连接和数据,也不会阻塞程序。NIO的服务器实现模式为一个线程可以处理多个请求(连接)。

NIO有几个知识点需要掌握,Channel(通道),Buffer(缓冲区), Selector(多路复用选择器)。

Channel既可以用来进行读操作,又可以用来进行写操作。NIO中常用的Channel有FileChannel
、SocketChannel、ServerSocketChannel、DatagramChannel。

Buffer缓冲区用来发送和接受数据。

Selector 一般称为选择器或者多路复用器 。它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。在javaNIO中使用Selector往往是将Channel注册到Selector中。

下面我通过代码的方式模拟javaNIO的运行流程。

(五)NIO代码实践
首先贴上NIO的实践代码:

NIO服务端详细的执行过程是这样的:

1、创建一个ServerSocketChannel和Selector,然后将ServerSocketChannel注册到Selector上

2、Selector通过select方法去轮询监听channel事件,如果有客户端要连接时,监听到连接事件。

3、通过channel方法将socketchannel绑定到ServerSocketChannel上,绑定通过SelectorKey实现。

4、socketchannel注册到Selector上,关心读事件。

5、Selector通过select方法去轮询监听channel事件,当监听到有读事件时,ServerSocketChannel通过绑定的SelectorKey定位到具体的channel,读取里面的数据。

线程模型

目前存在的线程模式:

  • 传统阻塞IO的服务模型
  • Reactor模式

根据Reactor的数量和1处理资源的线程数不同,又分3种:

  • Reactor单线程;
  • Reactor多线程;
  • 主从Reactor多线程

Netty的线程模型是基于主从Reactor多线程做了改进。

2、传统阻塞IO的线程模型 采用阻塞IO获取输入的数据,每个连接都需要独立的线程来处理逻辑。存在的问题就是,当并发数很大时,就需要创建很多的线程,占用大量的资源。连接创建后,如果当前线程没有数据可读,该线程将会阻塞在读数据的方法上,造成线程资源浪费。

 

3、Reactor模式(分发者模式/反应器模式/通知者模式) 针对传统阻塞IO的模型,做了以下两点改进:

  • 基于IO复用模型:多个客户端共用一个阻塞对象,而不是每个客户端都对应一个阻塞对象
  • 基于线程池复用线程资源:使用了线程池,而不是每来一个客户端就创建一个线程

Reactor模式的核心组成:

  • Reactor:Reactor就是多个客户端共用的那一个阻塞对象,它单独起一个线程运行,负责监听和分发事件,将请求分发给适当的处理程序来进行处理
  • Handler:处理程序要完成的实际事件,也就是真正执行业务逻辑的程序,它是非阻塞的

4、单线程Reactor

 

 

多个客户端请求连接,然后Reactor通过selector轮询判断哪些通道是有事件发生的,如果是连接事件,就到了Acceptor中建立连接;如果是其他读写事件,就有dispatch分发到对应的handler中进行处理。这种模式的缺点就是Reactor和Handler是在一个线程中的,如果Handler阻塞了,那么程序就阻塞了。

5、Reactor多线程

 

 

处理流程如下:

  • Reactor对象通过Selector监听客户端请求事件,通过dispatch进行分发;
  • 如果是连接事件,则由Acceptor通过accept方法处理连接请求,然后创建一个Handler对象响应事件;
  • 如果不是连接请求,则由Reactor对象调用对应handler对象进行处理;handler只响应事件,不做具体的业务处理,它通过read方法读取数据后,会分发给线程池的某个线程进行业务处理,并将处理结果返回给handler;
  • handler收到响应后,通过send方法将结果返回给client。

相比单Reactor单线程,这里将业务处理的事情交给了不同的线程去做,发挥了多核CPU的性能。但是Reactor只有一个,所有事件的监听和响应,都由一个Reactor去完成,并发性还是不好。

6、主从Reactor多线程

 

 

这个模型相比单reactor多线程的区别就是:专门搞了一个MainReactor来处理连接事件,如果不是连接事件,就分发给SubReactor进行处理。图中这个SubReactor只有一个,其实是可以有多个的,所以性能就上去了。

  • 优点:父线程与子线程的交互简单、职责明确,父线程负责接收连接,子线程负责完成后续的业务处理;
  • 缺点:编程复杂度高

Netty线程模型

netty模型是基于主从Reactor多线程模型设计的。

  • Netty有两组线程池,一个Boss Group,它专门负责客户端连接,另一个Work Group,专门负责网络读写;
  • Boss Group和Work Group的类型都是NIOEventLoopGroup;
  • NIOEventLoopGroup相当于一个事件循环组,这个组包含了多个事件循环,每一个循环都是NIOEventLoop;
  • NIOEventLoop表示一个不断循环执行处理任务的线程,每个NIOEventLoop都有一个Selector,用于监听绑定在其上的ocketChannel的网络通讯;
  • Boss Group下的每个NIOEventLoop的执行步骤有3步:

(1). 轮询accept连接事件;

(2). 处理accept事件,与client建立连接,生成一个NioSocketChannel,并将其注册到某个work group下的NioEventLoop的selector上;

(3). 处理任务队列的任务,即runAllTasks;

  • 每个Work Group下的NioEventLoop循环执行以下步骤:

(1). 轮询read、write事件;

(2). 处理read、write事件,在对应的NioSocketChannel处理;

(3). 处理任务队列的任务,即runAllTasks;

  • 每个Work Group下的NioEventLoop在处理NioSocketChannel业务时,会使用pipeline(管道),管道中维护了很多 handler 处理器用来处理 channel 中的数据。

 我的列子是单线的如下:

 

server:

package com.cn.jettech.jettoproimage.controller.imagecontroller01.imagecontroller01.io.nio;import org.springframework.expression.spel.ast.Selection;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 NIOServer {public static void main(String[] args) throws  Exception{//创建一个socket通道,并且设置为非阻塞的方式ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);serverSocketChannel.socket().bind(new InetSocketAddress(8080));//创建一个selector选择器,把channel注册到selector选择器上Selector selector = Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true){System.out.println("等待事件发生");selector.select();System.out.println("有事件发生了");Iterator<SelectionKey> selectionKeyIterator = selector.selectedKeys().iterator();while (selectionKeyIterator.hasNext()) {SelectionKey key = selectionKeyIterator.next();selectionKeyIterator.remove();handle(key);}}}private static void handle(SelectionKey key) throws Exception{if(key.isAcceptable()) {System.out.println("连接事件发生");ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel();//创建客户端一侧的channel,并注册到selector上SocketChannel clientChannel = serverSocketChannel.accept();clientChannel.configureBlocking(false);clientChannel.register(key.selector(),SelectionKey.OP_READ);} else if (key.isReadable()) {System.out.println("数据可读事件发生");SocketChannel clientChannel = (SocketChannel)key.channel();ByteBuffer serverBuffer = ByteBuffer.allocate(1024);int len = clientChannel.read(serverBuffer);if(len != 1) {System.out.println("读取到客户端发送的数据:"+new String(serverBuffer.array(),0,len));}//给客户端发送信息ByteBuffer clientBuffer = ByteBuffer.wrap("hello world".getBytes());clientChannel.write(clientBuffer);key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE);clientChannel.close();}}
}

client:
 

package com.cn.jettech.jettoproimage.controller.imagecontroller01.imagecontroller01.io.nio;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;public class NIOClient {public static void main(String[] args) throws  Exception{//配置基本的连接参数SocketChannel socketChannel=SocketChannel.open();socketChannel.configureBlocking(false);Selector selector = Selector.open();socketChannel.connect(new InetSocketAddress("127.0.0.1",8080));socketChannel.register(selector, SelectionKey.OP_CONNECT);//轮询访问selectorwhile (true){selector.select();Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()){SelectionKey key = iterator.next();iterator.remove();//连接事件发生if (key.isConnectable()){SocketChannel clientChannel = (SocketChannel)key.channel();//如果正在连接,则完成连接if (socketChannel.isConnectionPending()){socketChannel.finishConnect();}socketChannel.configureBlocking(false);ByteBuffer buffer = ByteBuffer.wrap("客户端发送的数据".getBytes());socketChannel.write(buffer);socketChannel.register(selector,SelectionKey.OP_READ);} else if (key.isReadable()) {//读取服务端发送过来的消息read(key);}}}}private static void read(SelectionKey key) throws Exception{SocketChannel socketChannel= (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(512);int len=socketChannel.read(buffer);if (len!=-1){System.out.println("客户端收到信息:"+new String(buffer.array(),0,len));}}
}

NIO练习:

package com.cn.jettech.jettoproimage.controller.imagecontroller01.imagecontroller01.io.nio;import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;public class NIOTest1 {public static void main(String[] args) throws  Exception {FileChannel fileChannel = new RandomAccessFile("G:\\work\\a.txt","rw").getChannel();System.out.println(fileChannel.size());MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE,fileChannel.position(),fileChannel.size());ByteBuffer byteBuffer = ByteBuffer.allocate(19);int read_size = fileChannel.read(mappedByteBuffer);while (read_size > 0) {System.out.println(fileChannel.position());mappedByteBuffer.flip();while (mappedByteBuffer.remaining() > 0) {System.out.print((char)mappedByteBuffer.get());}mappedByteBuffer.clear();read_size = fileChannel.read(mappedByteBuffer);}}
}

server:

package com.cn.jettech.jettoproimage.controller.imagecontroller01.imagecontroller01.io.nio;import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;public class NIOTest2 {private static Map<String,SocketChannel> clientMap = new HashMap<String,SocketChannel>();public static void main(String[] args) throws  Exception {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);serverSocketChannel.socket().bind(new InetSocketAddress(8899));Selector selector = Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {int select_num = selector.select();System.out.println(select_num);Set<SelectionKey> selectionKeySets = selector.selectedKeys();selectionKeySets.forEach(selectionKeySet -> {final SocketChannel client;System.out.println("aaaaaaaaaaaaaa");try {if(selectionKeySet.isAcceptable()){ServerSocketChannel server = (ServerSocketChannel)selectionKeySet.channel();client = server.accept();client.configureBlocking(false);client.register(selector,SelectionKey.OP_READ);String key = "[" + UUID.randomUUID().toString() +"]";clientMap.put(key,client);}else if (selectionKeySet.isReadable()) {client = (SocketChannel)selectionKeySet.channel();ByteBuffer readByteBuffer = ByteBuffer.allocate(1024);int count = client.read(readByteBuffer);if(count > 0){readByteBuffer.flip();Charset charset = Charset.forName("UTF-8");String receiveMessage = String.valueOf(charset.decode(readByteBuffer).array());System.out.println(client + ":" +receiveMessage);String senderKey = null;for(Map.Entry<String,SocketChannel> stringSocketChannelEntry : clientMap.entrySet()){if(client == stringSocketChannelEntry.getValue()){senderKey = stringSocketChannelEntry.getKey();break;}}for (Map.Entry<String,SocketChannel> stringSocketChannelEntry : clientMap.entrySet()) {SocketChannel value = stringSocketChannelEntry.getValue();ByteBuffer writeByteBuffer = ByteBuffer.allocate(1024);writeByteBuffer.put((senderKey +":" + receiveMessage).getBytes());writeByteBuffer.flip();value.write(writeByteBuffer);}}}selectionKeySets.remove(selectionKeySet);} catch (IOException e) {e.printStackTrace();}});}}
}

客户端:

[root@localhost jettech-actuator-api]# nc 192.168.0.17 8899
adasd
asdasd
sadasd
asdas
dasd
asd
asd^C或[root@localhost jettech-actuator-api]# telnet  192.168.0.17 8899
Trying 192.168.0.17...
Connected to 192.168.0.17.
Escape character is '^]'.
wubo

(六)NIO总结
NIO通过一个Selector,负责监听各种IO事件的发生,然后交给后端的线程去处理。NIO相比与BIO而言,非阻塞体现在轮询处理上。BIO后端线程需要阻塞等待客户端写数据,如果客户端不写数据就一直处于阻塞状态。而NIO通过Selector进行轮询已注册的客户端,当有事件发生时才会交给后端去处理,后端线程不需要等待。
 

(七)什么是AIO
AIO是在JDK1.7中推出的新的IO方式–异步非阻塞IO,也被称为NIO2.0,AIO在进行读写操作时,直接调用API的read和write方法即可,这两种均是异步的方法,且完成后会主动调用回调函数。简单来讲,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。

Java提供了四个异步通道:AsynchronousSocketChannel、AsynchronousServerSocketChannel、AsynchronousFileChannel、AsynchronousDatagramChannel。

(八)AIO代码实践
server:

package com.cn.jettech.jettoproimage.controller.imagecontroller01.imagecontroller01.io.aio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.TimeUnit;public class AIOServer {public static void main(String[] args) {try {AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8899));System.out.println("wait connect ----");// 第一个参数是一个泛型,可以用来控制想传递的对象// 第二个参数CompletionHandler,用来处理监听成功和失败的逻辑//  如此设置监听的原因是因为这里的监听是一个类似于递归的操作,每次监听成功后要开启下一个监听serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {@Overridepublic void completed(AsynchronousSocketChannel result, Object attachment) {System.out.println("连接成功,处理数据中");serverSocketChannel.accept(null,this);handledata(result);}@Overridepublic void failed(Throwable exc, Object attachment) {System.out.println("失败");}});try {TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();}} catch (IOException e) {e.printStackTrace();}}private  static void handledata(AsynchronousSocketChannel result) {ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//通道的read方法也带有三个参数//1.目的地:处理客户端传递数据的中转缓存,可以不使用//2.处理客户端传递数据的对象//3.处理逻辑,也有成功和不成功的两个写法result.read(byteBuffer, byteBuffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer attachment) {if(result > 0) {attachment.flip();byte[] array = attachment.array();System.out.println(new String(array).trim());attachment.clear();}}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {System.out.println("失败");}});}
}

client:

package com.cn.jettech.jettoproimage.controller.imagecontroller01.imagecontroller01.io.aio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.Scanner;public class AIOClient {public static void main(String[] args) {try {AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();socketChannel.connect(new InetSocketAddress("127.0.0.1",8899));Scanner scanner = new Scanner(System.in);String next = scanner.next();ByteBuffer byteBuffer = ByteBuffer.allocate(1024);byteBuffer.put(next.getBytes());byteBuffer.flip();socketChannel.write(byteBuffer);} catch (IOException e) {throw new RuntimeException(e);}}
}

Java BIO、NIO、AIO_java nio bio uio_Ang Ga Ga的博客-CSDN博客

超详细的 Netty 入门 - 知乎


http://chatgpt.dhexx.cn/article/t1AupWAF.shtml

相关文章

TensorFlow2.0学习笔记-3.模型训练

3.模型训练 3.1.Keras版本模型训练 • 构建模型&#xff08;顺序模型、函数式模型、子类模型&#xff09; • 模型训练&#xff1a; model.fit() • 模型验证&#xff1a; model.evaluate() • 模型预测&#xff1a; model.predict() • 使用样本加权和类别加权 回调函数 •…

sql注入学习

提示&#xff1a;萌新学习路程的记录型文章&#xff0c;有错误的地方欢迎大佬们指正。 文章目录 前言一、SQLi-Labs1、SQLi-Labs下载、安装&#xff08;环境搭建)(1) 首先下载解压并移动sqli-labs(2) 找到sql-connections下的db-creds.inc进行修改(3) 打开网页&#xff1a;http…

从客户端中检测到有潜在危险的 request.form值[解决方法]

当页面编辑或运行提交时,出现“从客户端中检测到有潜在危险的request.form值”问题,该怎么办呢?如下图所示: 下面博主汇总出现这种错误的几种解决方法:问题原因:由于在asp.net中,Request提交时出现有html代码或javascript等字符串时,程序系统会认为其具有潜在危险的值。…

sadadas

dasdasdasdasdasd

python_day3_集合与运算/文件读写、修改详解/字符编码转换/函数和函数式编程(return/参数详解/局部变量与全局变量/递归/高阶函数)

Python_集合与运算/文件读写、修改详解/字符编码详解/函数和函数式编程/函数式编程之参数/局部变量与全局变量/递归/高阶函数 在这里得感谢&#xff0c;老师Alex金角大王(路飞学城IT) Python(给兄弟们挂个&#x1f517;) >_<…因为有的是自己理解&#xff0c;如有错误&a…

svn添加新项目的步骤

1.服务端给一个地址&#xff1a;拉取代码 2.上传代码&#xff08;不含没有module的build文件夹和以下文件夹&#xff09;

项目新添加页面svn上传

你项目当中新添加了页面上传SVN&#xff0c;需要先把新添加的页面Add到SVN上&#xff0c; 右击新添加的页面出现TortoiseSVN — Add&#xff0c;然后上传整个项目就可以了&#xff0c;SVN上就有新添加的页面了。 如下图

Eclipse用SVN上传新项目

首先右击项目–>team --> share project 选择repository为svn–>点击next 使用已有的资源库的位置&#xff0c;如下图所示&#xff1a; 使用项目名称作为文件夹名 --> 点击Finish --> 输入用户名和密码(此步不一定每个人都有)&#xff0c;如下图所示&#xff1a…

IDEA添加新项目到SVN

1.打开IDEA &#xff0c;上面工具栏选择VCS 选择把项目交给SVN管理 2.选择SVN 3、右键项目选择如下 4.点击绿色的号&#xff0c;选择一个SVN仓库的地址&#xff0c;下面可以选择上传到SVN仓库的目录格式&#xff0c;然后点击Share 5.默认1.8 6.右键项目选择-->Subversion--…

项目上传到SVN

步骤1、首先在服务器上安装svn。 步骤2、然后找到svn 选择VisualSVN Server Manager 在Repositories下新建Repository name 步骤3、在MyEclipse中右击项目&#xff0c;Team–>Share Project–>SVN–>创建新的资源位置或使用已有的资源位置&#xff08;最好新建&#…

idea上传新项目至svn仓库

linux下安装svn服务器&#xff0c;idea上传新项目 linux下安装svn服务器,配置svn仓库 就不写了,百度一大把 导入项目: 点击号 linux下svn://开头,输入svn服务器创建的仓库地址,也可连接http:// 输入svn仓库配置的账号.密码 导入

Eclipse中SVN上传项目

上传新项目到SVN服务器 选中你要上传的项目&#xff0c;右键-->Team-->Share Project&#xff0c;选中SVN-->Next。 前提是已经安装SVN插件&#xff1a;https://blog.csdn.net/weixin_44306005/article/details/95487732 如图所示进行下一步操作&#xff1a; 如图所…

IDEA使用SVN上传项目

1、设置SVN 2、在settings→Version Control中可以改变版本控制 3、右键项目选择如下 4、添加仓库地址 5、点击share提交 6、文件颜色由红变绿 7、右键选择commit 一路选择commit 7、如果在IDEA中上传太慢,可以选择在项目文件中直接使用SVN上传 PS&#xff1a;如果账号有问题,…

IDEA如何将上传项目到SVN

1.打开IDEA &#xff0c;上面工具栏选择VCS 选择把项目交给SVN管理 2.选择SVN 3、选择SVN管理后可以看到项目变砖红色颜色 4、右键项目选择如下 5、点击绿色的号&#xff0c;选择一个SVN仓库的地址&#xff0c;下面可以选择上传到SVN仓库的目录格式&#xff0c;然后点击Shard…

linuxsvn服务器导入项目,linux svn 导入项目

linux svn 导入项目 内容精选 换一换 用于将其它云端仓库导入到代码托管服务中&#xff0c;也可以将代码托管服务中一个区域的仓库导入到另一个区域(异地备份)&#xff0c;导入后的仓库与源仓库彼此独立。在代码托管服务控制台导入外部仓库的步骤如下&#xff1a;外部仓库可以是…

在Linux服务器上安装SVN并上传项目

安装svn &#xff08;1&#xff09;安装svn服务器&#xff1a; yum install subversion&#xff08;2&#xff09;查看版本&#xff08;随自己意愿&#xff09;&#xff1a; svnserve --version创建svn仓库并配置 &#xff08;1&#xff09;创建svn仓库 在/home下创建svn目…

LINUX SVN 新建项目

从第三方代码创建代码库&#xff1a; 1、通过客户端进入服务端 2、在对应的目录创建新的项目/目录 在对应的目录右击 &#xff1a;creat folder... 例&#xff1a;创建testSvn 3、在客户端checkout(co) testSvn 4、将第三方源码(srcTest)拷贝到客户端下的对应路径 防止L…

IDEA上传项目到SVN

一、什么是SVN SVN就是用来进行版本控制的工具&#xff0c;主要用于团队协作开发&#xff0c;和历史版本恢复等。 SVN分为服务端和客户端 推荐使用&#xff1a; 1、服务端&#xff1a;VisualSVN Sever 说明&#xff1a;用来创建项目仓库&#xff08;存放项目用的&#xff0…

如何将Android新项目上传到SVN服务器

1.前提是你已经有仓库&#xff0c;有账号密码&#xff0c;如何新建仓库&#xff0c;配置svn这些这里不详细说。我们首次在一个svn的仓库中新建一个文件夹&#xff0c;用来存放我们的项目&#xff0c;请看如下图。 这里要你输入文件夹的名称&#xff0c;点击ok。看图 我新建的…

IDEA如何上传项目到SVN、IDEA将项目发布到svn

第一步&#xff0c; 从idea上传项目到svn 第二步&#xff0c;将idea中的项目与svn进行关联