网络编程NIO:BIO和NIO详解,看不懂你打我
BIOBIO(Blocking I/O) , 同步阻塞 , 实现模式为一个连接一个线程 , 即当有客户端连接时 , 服务器端需为其单独分配一个线程 , 如果该连接不做任何操作就会造成不必要的线程开销 。 BIO是传统的java io编程 , 其相关的类和接口在java.io 包下 。
BIO适用于连接数目较小且固定的架构 , 对服务器资源的要求较高 , 是JDK1.4以前的唯一选择 , 但程序简单易理解 。
文章插图
BIO编程流程
- 服务器端启动一个SeverSocket
- 客户端启动Socket对服务器端发起通信 , 默认情况下服务器端需为每个客户端创建一个线程与之通讯
- 客户端发起请求后 , 先咨询服务器端是否有线程响应 , 如果没有则会等待或被拒绝
- 如果有线程响应 , 客户端线程会等待请求结束后 , 再继续执行
//BIO-服务器端public class BIOSever {public static void main(String[] args) throws IOException {//在BIO中 , 可以使用线程池进行优化ExecutorService cachedThreadPool = Executors.newCachedThreadPool();ServerSocket serverSocket = new ServerSocket(6666);System.out.println("服务器已启动");while (true){System.out.println("等待客户端连接.....(阻塞中)");Socket socket = serverSocket.accept();System.out.println("客户端连接");cachedThreadPool.execute(new Runnable() {public void run() {handler(socket);}});}}//从客服端socket读取数据public static void handler(Socket socket){try{InputStream inputStream = socket.getInputStream();byte[] b = new byte[1024];while (true){System.out.println("等待客户端输入.....(阻塞中)");int read = inputStream.read(b);if (read != -1){System.out.println(new String(b, 0, read));}else {break;}}inputStream.close();}catch (Exception e){e.printStackTrace();}finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
//BIO-客户端public class BIOClient {public static void main(String[] args) throws IOException {Socket socket = new Socket("localhost", 6666);OutputStream outputStream = socket.getOutputStream();Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()){String message = scanner.nextLine();if ("exit".equals(message)) {break;}outputStream.write(message.getBytes());}outputStream.close();socket.close();}}
BIO问题分析从上面代码中可以看出BIO编程的两个问题:- 服务器端在监听客户端连接时(serverSocket.accept()) , 服务器端处于阻塞状态 , 不能处理其他事务
- 服务器端需要为每个客户端建立一个线程 , 虽然可以用线程池来优化 , 但在并发较大时 , 线程开销依旧很大
- 当连接的客户端没有发送数据时 , 服务器端会阻塞在read操作上 , 等待客户端输入 , 造成线程资源浪费
文章插图
NIO的三大核心缓冲区(Buffer)NIO是面向缓冲区, 或者说是面向块编程的 。 在NIO的IO传输中 , 数据会先读入到缓冲区 , 当需要时再从缓冲区写出 , 这样减少了直接读写磁盘的次数 , 提高了IO传输的效率 。
缓冲区(buffer)本质上是一个可以读写数据的内存块 , 即在内存空间中预留了一定的存储空间 , 这些存储空间用来缓冲输入和输出的数据 , 这部分预留的存储空间就叫缓冲区 。
在NIO程序中 , 通道channel虽然负责数据的传输 , 但是输入和输出的数据都必须经过缓冲区buffer 。
文章插图
在java中 , 缓冲区的相关类都在java.nio包下 , 其最顶层的类是 Buffer , 它是一个抽象类 。
Buffer类的4个重要属性:
- mark:标记
- position:位置 , 下一个要被读或写的元素的索引 , 每次读写缓冲区都会改变该值 , 为下次读写做准备
- limit:表示缓冲区的终点 , 不能对缓冲区中超过极限的位置进行读写操作 , 且极限是可修改的
- capacity:容量 , 即缓冲区的最多可容纳的数据量 , 该值在创建缓冲区时被设立 , 且不可修改
文章插图
Buffer的常用子类(它们之间最大区别在于底层实现数组的数据类型):
- ByteBuffer:存储字节数据到缓冲区
- EVGA RTX3080更新BIOS 显卡功耗提升至450W
- 华硕发布400系主板新BIOS:Intel酷睿也支持AMD SAM了
- 常用的NIO框架-Netty
- OS|蔚来发布NIO OS 2.8.0版本更新 11月30日分批推送
- 技嘉500系列主板升级BIOS:3A平台打鸡血 性能白捡17%
- AMD RX 6900 XT BIOS信息曝光:最高GPU时钟频率3.0GHz
- 参与|CompanionPro:无需人参与的狗狗AI训练机器
- Apple|摩托罗拉新机 Nio 曝光,Apple M1 芯片安兔兔跑分曝光
- 摩托罗拉|摩托罗拉Nio智能手机传搭配105Hz刷新率显示屏
- 摩托罗拉Nio智能手机传搭配105Hz刷新率显示屏