BIO與NIO
1.傳統BIO
(1)特色
- 面向數據流
- 阻塞式傳輸
- 一個客戶端對應一個線程
- 在客戶機增多的狀況下,線程資源隨之增多,會形成cpu資源枯竭
(2)需求
客戶機向服務器輸出字符串,逐一在服務器器上打印顯示。相似一個簡陋的聊天室功能。java
(3)代碼示例
-
服務器程序TimeServer.javaapi
package com.xm.bio; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class TimeServer { public static void main(String[] args) throws IOException { int port = 8080; if(args != null && args.length>0) { try { port = Integer.parseInt(args[0]); } catch (Exception e) { } } ServerSocket server = null; try { server = new ServerSocket(port); System.out.println("開啓服務器:"+server.getLocalSocketAddress()); Socket socket = null; while(true) { socket = server.accept(); new Thread(new TimeServerHandle(socket)).start(); } } finally { if(server != null) { System.out.println("服務器已關閉!"); server.close(); server = null; } } } }
-
服務器處理客戶機進程TimeServerHandle.java服務器
package com.xm.bio; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Date; public class TimeServerHandle implements Runnable { private Socket socket; public TimeServerHandle(Socket socket) { this.socket = socket; } @Override public void run() { System.out.println(socket.getInetAddress().toString()+"客戶機已鏈接"); BufferedReader in = null; PrintWriter out = null; BufferedReader wt = null; try { in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); wt = new BufferedReader(new InputStreamReader(System.in)); while(true) { System.out.println(in.readLine()); } } catch (Exception e) { } finally { if(in != null) { try { in.close(); in = null; } catch (IOException e) { e.printStackTrace(); } } if(out != null) { out.close(); out = null; } if(socket != null) { try { socket.close(); socket = null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
-
客戶端程序TimeClient.java網絡
package com.xm.bio; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class TimeClient { public static void main(String[] args) { int port = 8080; String host = "127.0.0.1"; Socket socket = null; BufferedReader in = null; BufferedReader wt = null; PrintWriter out = null; try { socket = new Socket(host, port); wt = new BufferedReader(new InputStreamReader(System.in)); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); String body = null; while(true) { String str = wt.readLine(); out.println(str); } } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { try { wt.close(); in.close(); out.close(); socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
2.NIO
(1)NIO特色
1.面向緩衝區 2.傳輸方式爲管道傳輸 3.非阻塞 4.支持大併發下的io處理併發
(2)NIO下的本地文件傳輸
-
內存映射下的緩衝通道app
package com.xm.nio; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.time.Duration; import java.time.Instant; import org.junit.jupiter.api.Test; public class NIOFileDemo { /** * 1.經過流獲取通道 */ @Test public void test1() { Instant begin = Instant.now(); //1.定義文件流 FileInputStream fis = null; FileOutputStream fos = null; //2.獲取通道 FileChannel inChannel = null; FileChannel outChannel = null; try { fis = new FileInputStream("1.jpg"); fos = new FileOutputStream("2.jpg"); inChannel = fis.getChannel(); outChannel = fos.getChannel(); //3.定義緩衝區 ByteBuffer buffer = ByteBuffer.allocate(1024); //4.讀取數據到緩衝區,再從緩衝區寫入到文件 while(inChannel.read(buffer) != -1) { //切換到讀模式 buffer.flip(); //寫操做到管道 outChannel.write(buffer); //清空buffer buffer.clear(); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { //5.關閉通道和流 if(inChannel != null) { try { inChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(outChannel != null) { try { outChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(fis != null) { try { fis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(fos != null) { try { fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } Instant end = begin.plus(Duration.ofSeconds(10)); System.out.println("Difference in milliseconds : " + Duration.between(begin, end).toMillis()); } /** * 經過文件獲取管道 */ @Test public void test2() { Instant begin = Instant.now(); FileChannel inChannel =null; FileChannel outChannel = null; try { inChannel =FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); /** * StandardOpenOption.CREATE與StandardOpenOption.CREATE_NEW的區別 * 1.StandardOpenOption.CREATE:無則建立,有則覆蓋 * 2.StandardOpenOption.CREATE_NEW:無則建立,有則報錯 */ outChannel =FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE); //3.定義緩衝區 ByteBuffer buffer = ByteBuffer.allocate(1024); //4.讀取數據到緩衝區,再從緩衝區寫入到文件 while(inChannel.read(buffer) != -1) { //切換到讀模式 buffer.flip(); //寫操做到管道 outChannel.write(buffer); //清空buffer buffer.clear(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { //5.關閉通道和流 if(inChannel != null) { try { inChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(outChannel != null) { try { outChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } Instant end = begin.plus(Duration.ofSeconds(10)); System.out.println("Difference in milliseconds : " + Duration.between(begin, end).toMillis()); } }
-
物理映射下的緩衝通道異步
package com.xm.nio; import java.io.IOException; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.time.Duration; import java.time.Instant; import org.junit.Test; public class NIOFileDemo2 { /** * 使用直接緩衝區傳輸 */ @Test public void test1() { Instant begin = Instant.now(); FileChannel inChannel = null; FileChannel outChannel = null; try { //1.開啓通道 inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE,StandardOpenOption.READ); //2.定義物理緩衝區 MappedByteBuffer inBuffer = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size()); MappedByteBuffer outBuffer = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size()); //3.緩衝區讀寫操做 byte[] dst = new byte[inBuffer.limit()]; inBuffer.get(dst); outBuffer.put(dst); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { //4.關閉通道 if(null != inChannel) { try { inChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(null != outChannel) { try { outChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } Instant end = begin.plus(Duration.ofSeconds(10)); System.out.println("Difference in milliseconds : " + Duration.between(begin, end).toMillis()); } /** * 通道之間的傳輸 */ @Test public void test2() { Instant begin = Instant.now(); FileChannel inChannel = null; FileChannel outChannel = null; //獲取通道 try { inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE); //通道間傳輸 //1.to操做 //inChannel.transferTo(0, inChannel.size(), outChannel); //2.from操做 outChannel.transferFrom(inChannel, 0, inChannel.size()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { //4.關閉通道 if(null != inChannel) { try { inChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(null != outChannel) { try { outChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } Instant end = begin.plus(Duration.ofSeconds(10)); System.out.println("Difference in milliseconds : " + Duration.between(begin, end).toMillis()); } }
(3)NIO下的網絡傳輸
-
阻塞式socket
-
服務端程序ide
package com.xm.nio.block; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Scanner; public class NIOServer { public static void main(String[] args) throws IOException { int port = 8989; //1.獲取通道 ServerSocketChannel serverChannel = ServerSocketChannel.open(); //2.綁定端口號 serverChannel.bind(new InetSocketAddress(port)); //3.獲取客戶端鏈接 SocketChannel socketChannel = serverChannel.accept(); //定義文件傳輸通道 FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE); ByteBuffer buffer = ByteBuffer.allocate(1024); while(socketChannel.read(buffer)!=-1) { buffer.flip(); outChannel.write(buffer); buffer.clear(); } outChannel.close(); socketChannel.close(); } }
-
客戶端程序this
package com.xm.nio.block; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.SocketChannel; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; public class NIOClient { public static void main(String[] args) throws IOException { int port = 8989; //1.獲取通道 SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", port)); //2.獲取文件通道 FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); inChannel.transferTo(0, inChannel.size(), socketChannel); //3.關閉通道 inChannel.close(); socketChannel.close(); } }
-
-
非阻塞式
-
服務端程序
package com.xm.nio.noblock; 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.ArrayList; import java.util.Iterator; import java.util.List; public class NIOServer { public static void main(String[] args) throws IOException { int port = 8989; //1.開啓通道 ServerSocketChannel serverChannel = ServerSocketChannel.open(); //2.綁定端口號 serverChannel.bind(new InetSocketAddress(port)); //3.設置非阻塞 serverChannel.configureBlocking(false); //4.開啓選擇器 Selector selector = Selector.open(); //5.註冊鏈接監聽 serverChannel.register(selector, SelectionKey.OP_ACCEPT); List<SocketChannel> channels = new ArrayList<>(); while(selector.select() > 0) { Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); while(keys.hasNext()) { SelectionKey key = keys.next(); if(key.isAcceptable()) { SocketChannel socketChannel = serverChannel.accept(); channels.add(socketChannel); System.out.println("客戶端鏈接成功:"+socketChannel.getLocalAddress()+" hashcode:"+socketChannel.hashCode()); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } else if(key.isReadable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer dst = ByteBuffer.allocate(1024); int len; while(-1 != (len=socketChannel.read(dst))) { dst.flip(); System.out.println(new String(dst.array(),0,len)); /*for(SocketChannel sChannel:channels) { if(sChannel != socketChannel) { dst.flip(); sChannel.write(dst); } }*/ dst.clear(); } } } keys.remove(); } } }
-
客戶端
package com.xm.nio.noblock; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Iterator; import java.util.Scanner; public class NIOClient{ SocketChannel socketChannel; public NIOClient() throws IOException { int port = 8989; //1.獲取通道 socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", port)); //2.設置異步非阻塞 socketChannel.configureBlocking(false); //2.獲取文件通道 FileChannel inChannel = FileChannel.open(Paths.get("1.md"), StandardOpenOption.READ); inChannel.transferTo(0, inChannel.size(), socketChannel); //3.關閉通道 inChannel.close(); socketChannel.close(); } public static void main(String[] args) { try { new NIOClient(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-