简述BIO/NIO/AIO前世今生
如下程序是简单实现了一个极其简单的WEB服务器,用来监听某个端口,接受客户端输入输出信息。
但这个程序有一个致命的问题就是连接会长时间阻塞
于是BIO版本出现了,改成了 一个连接 一个线程来处理请求
此时主程序会立即返回并等待下一个连接。但这个程序的问题是 每次一个连接 需要单独创建一个线程,服务器线程资源是优先的,而且1000个连接 有可能有效的读、写事件更少,所以NIO做法是一个
归类问题:
- 每个请求都需要创建独立的线程,与对应的客户端进行数据处理。
- 当并发数大时,需要
创建大量线程来处理连接
,系统资源占用较大。 - 连接建立后,如果当前线程暂时没有数据可读,则当前线程会一直阻塞在 Read 操作上,造成线程资源浪费
NIO
下面附上一段NIO简易代码说明问题
1) 监听的事件有 OP_ACCEPT: 接收就绪,ServerSocketChannel使用的 OP_READ: 读取就绪,socketChannel使用 OP_WRITE: 写入就绪,socketChannel使用 OP_CONNECT: 连接就绪,socketChannel使用 2) public static void main(String[] args) throws IOException { ServerSocketChannel ssc = ServerSocketChannel.open();//管道型ServerSocket ssc.socket().bind(new InetSocketAddress(Constant.HOST, Constant.PORT)); ssc.configureBlocking(false);//设置非阻塞 System.out.println(" NIO single server started, listening on :" + ssc.getLocalAddress()); //Selector选择器可以监听多个Channel通道感兴趣的事情(read、write、accept(服务端接收)、connect,实现一个线程管理多个Channel,节省线程切换上下文的资源消耗。Selector只能管理非阻塞的通道,FileChannel是阻塞的,无法管理 Selector selector = Selector.open(); ssc.register(selector, SelectionKey.OP_ACCEPT);// 就绪事件【在建立好的管道上,注册关心的事件】 while(true) { selector.select(); Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> it = keys.iterator(); while(it.hasNext()) { SelectionKey key = it.next(); it.remove();//处理的事件,必须删除 handle(key); } } } /** * SocketChannel:从TCP网络中读取或者写入数据。 * ServerSocketChannel:允许你监听来自TCP的连接,就像服务器一样。每一个连接都会有一个SocketChannel产生。 */ private static void handle(SelectionKey key) throws IOException { if(key.isAcceptable()) { ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
/**
*
如果此通道处于非阻塞模式,则此方法将立即返回NULL
*否则它将无限期阻塞,直到有新连接可用为止
*或发生I / O错误。
@return 返回新创建的连接socketChannel
或者返回NULL如果此通道处于非阻塞模式)
*并且无法接受任何连接
*/
SocketChannel sc = ssc.accept(); sc.configureBlocking(false);//设置非阻塞 sc.register(key.selector(), SelectionKey.OP_READ );//[可读]在建立好的管道上,注册关心的事件 } else if (key.isReadable()) { //flip SocketChannel sc = null; sc = (SocketChannel)key.channel(); ByteBuffer buffer = ByteBuffer.allocate(512); buffer.clear(); int len = sc.read(buffer); if(len != -1) { System.out.println("[" +Thread.currentThread().getName()+"] recv :"+ new String(buffer.array(), 0, len)); } ByteBuffer bufferToWrite = ByteBuffer.wrap("HelloClient".getBytes()); sc.write(bufferToWrite); } }
标签:
NIO
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?