IO/NIO交互模拟及渐进式实现

编程入门 行业动态 更新时间:2024-10-18 08:19:14

IO/NIO交互模拟及<a href=https://www.elefans.com/category/jswz/34/1757769.html style=渐进式实现"/>

IO/NIO交互模拟及渐进式实现

IO

IO Server

public class SocketServer {public static void main(String[] args)  {//server编号和client编号对应,优缺点注释在server端//server1();//server2();server3();}/*** server1的缺点:* 1、accept()方法阻塞了线程,要等客户端连接后才能继续处理(一个客户端连接,对应一个服务端处理线程)* 2、当客户端与服务端完成一次交互后,程序就结束了* 3、流关闭代码比较臃肿、BufferedWriter的内容需要在末尾加'\n'* 4、交互的内容写死,不可以通过控制台输入* 5、端口号固定、ip固定、readLine读取一行等等*/public static void server1() {ServerSocket serverSocket = null;BufferedReader bufferedReader = null;BufferedWriter bufferedWriter = null;try {serverSocket = new ServerSocket(8999);//阻塞至客户端连接成功Socket socket = serverSocket.accept();bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//readLine会阻塞String s = bufferedReader.readLine();System.out.println("服务端接收到客户端的消息:" + s);bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bufferedWriter.write("服务端发送消息给客户端\n");bufferedWriter.flush();} catch (IOException e) {throw new RuntimeException(e);} finally {//各个try catch 必须分开写,聚合成一个会导致一个流关闭异常,无法进入其他流的关闭流程if(serverSocket != null) {try {serverSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}if(bufferedWriter != null) {try {bufferedWriter.close();} catch (IOException e) {throw new RuntimeException(e);}}//只需要关闭外层的缓冲区,其close方法内部关闭了了传入的流//如果不关闭,只是等待jvm兜底finally,会在不确定的时间内对资源造成占用(如果是文件读写会对文件描述符fd的占用)if (bufferedReader != null) {try {bufferedReader.close();} catch (IOException e) {throw new RuntimeException(e);}}}}/*** server2优点:* 1、服务端和客户端可以任意次交互,可以连续发送消息* 2、优化了流关闭的写法** server2的缺点:* 1、accept()方法阻塞了线程,要等客户端连接后才能继续处理(一个客户端连接,对应一个服务端处理线程)* 2、cpu空转* 3、ip固定等等* 4、一个服务端只能和一个客户端交互*/public static void server2() {System.out.println("请输入端口号,并等待客户端连接...");try (BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));ServerSocket serverSocket = new ServerSocket(Integer.valueOf(consoleReader.readLine()));Socket socket = serverSocket.accept();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));){System.out.println("客户端已连接,开始和客户端交互...");//这个循环保证可以连续发送或者接收多条消息while (true) {if (bufferedReader.ready()) {System.out.println("收到客户端的消息:" + bufferedReader.readLine());}if (consoleReader.ready()) {printWriter.println(consoleReader.readLine());printWriter.flush();}}//只能发一次接收一次
//            while (true) {
//                System.out.println("收到客户端的消息:" + bufferedReader.readLine());
//
//                printWriter.println(consoleReader.readLine());
//                printWriter.flush();
//            }} catch (IOException e) {throw new RuntimeException(e);}}/*** server3优点:* 一个服务端可以和一个客户端交互* 加上了线程池** server3的缺点:* 1、accept()方法阻塞了线程,要等客户端连接后才能继续处理(一个客户端连接,对应一个服务端处理线程)* 2、cpu空转* 3、ip固定等等* 4、如果开启多个客户端,因System.in被服务端共享,所以服务端发送消息后,客户端会随机接收其中个别消息*/public static void server3() {ThreadPoolExecutor pool = new ThreadPoolExecutor(0, Runtime.getRuntime().availableProcessors() * 2,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());System.out.println("请输入端口号,并等待客户端连接...");try (BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));ServerSocket serverSocket = new ServerSocket(Integer.valueOf(consoleReader.readLine()));){//这个循环保证多个客户端连接while (true) {Thread.sleep(1000);Socket socket = serverSocket.accept();System.out.println("客户端已连接,开始和客户端交互...");pool.submit(new Thread(()->{try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));) {while (true) {Thread.sleep(1000);if(bufferedReader.ready()) {System.out.println("收到客户端"+ Thread.currentThread() +"的消息:" + bufferedReader.readLine());}if (consoleReader.ready()) {printWriter.println(consoleReader.readLine());printWriter.flush();}}} catch (IOException e) {throw new RuntimeException(e);} catch (InterruptedException e) {throw new RuntimeException(e);} finally {if(socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}));}} catch (IOException e) {throw new RuntimeException(e);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

IO Client

public class SocketClient {public static void main(String[] args) {//client1();//client2();client3();}public static void client1() {Socket socket = null;BufferedReader bufferedReader = null;BufferedWriter bufferedWriter = null;try {socket = new Socket("127.0.0.1", 8999);bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//换行符必不可少,不然服务端readLine()无法判断一行已经写完bufferedWriter.write("客户端发送消息给服务端\n");bufferedWriter.flush();bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));String s = bufferedReader.readLine();System.out.println("客户端接收到服务端的消息:" + s);} catch (IOException e) {throw new RuntimeException(e);} finally {if(socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}if(bufferedWriter != null) {try {bufferedWriter.close();} catch (IOException e) {throw new RuntimeException(e);}}if (bufferedReader != null) {try {bufferedReader.close();} catch (IOException e) {throw new RuntimeException(e);}}}}public static void client2() {System.out.println("请输入端口号:");try (BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));Socket socket = new Socket("127.0.0.1", Integer.valueOf(consoleReader.readLine()));PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));){System.out.println("连接成功,开始和服务端交互");//可以连续发送或者接收多条消息while (true) {Thread.sleep(1000);if (bufferedReader.ready()) {System.out.println("收到服务端的消息:" + bufferedReader.readLine());}if (consoleReader.ready()) {printWriter.println(consoleReader.readLine());printWriter.flush();}}//只能发一次接收一次
//            while (true) {
//                printWriter.println(consoleReader.readLine());
//                printWriter.flush();
//
//                System.out.println("收到服务端的消息:" + bufferedReader.readLine());
//            }} catch (IOException e) {throw new RuntimeException(e);} catch (InterruptedException e) {throw new RuntimeException(e);}}public static void client3() {System.out.println("请输入端口号:");try (BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));Socket socket = new Socket("127.0.0.1", Integer.valueOf(consoleReader.readLine()));PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));){System.out.println("连接成功,开始和服务端交互");//可以连续发送或者接收多条消息while (true) {if (bufferedReader.ready()) {System.out.println("收到服务端的消息:" + bufferedReader.readLine());}if (consoleReader.ready()) {printWriter.println(consoleReader.readLine());printWriter.flush();}}} catch (IOException e) {throw new RuntimeException(e);}}
}

NIO

NIO Server

public class SocketServer {public static void main(String[] args) {//server1();//server2();//server3();//server4();server5();}/*** 优点:NIO非阻塞方式,连接不会阻塞、读写不会阻塞* 缺点:* 1、当客户端与服务端完成一次交互后,程序就结束了* 2、交互的内容写死,不可以通过控制台输入* 3、cpu空转* 4、未使用selector多路复用器,其编程其实还是类似与BIO形式(服务端还是每个线程对应一个客户端)*/private static void server1() {try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();){serverSocketChannel.socket().bind(new InetSocketAddress(9999));serverSocketChannel.configureBlocking(false);//accept设置了非阻塞,因此需要放置在循环中使用,否则程序直接结束了while (true) {Thread.sleep(1000);SocketChannel socketChannel = serverSocketChannel.accept();if(socketChannel != null) {System.out.println("客户端已连接,开始和客户端交互...");socketChannel.configureBlocking(false);ByteBuffer readBuffer = ByteBuffer.allocate(1024);socketChannel.read(readBuffer);readBuffer.clear();System.out.println("接收到客户端消息: " + new String(readBuffer.array(), "utf-8").trim());ByteBuffer writeBuffer = ByteBuffer.wrap("发送消息给客户端".getBytes());socketChannel.write(writeBuffer);}}} catch (IOException e) {throw new RuntimeException(e);} catch (InterruptedException e) {throw new RuntimeException(e);}}/*** 改良:* 1、支持客户端和服务端一对一交互,多发* 缺点:* 1、不支持一个客户端对多个服务端* 2、如果开启多个客户端,因System.in被服务端共享,所以服务端发送消息后,客户端会随机接收其中个别消息* 3、cpu空转* 4、未使用selector多路复用器,其编程其实还是类似与BIO形式(服务端还是每个线程对应一个客户端)*/private static void server2() {try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));){serverSocketChannel.socket().bind(new InetSocketAddress(9999));serverSocketChannel.configureBlocking(false);//accept设置了非阻塞,因此需要放置在循环中使用,否则程序直接结束了while (true) {Thread.sleep(1000);SocketChannel socketChannel = serverSocketChannel.accept();if(socketChannel != null) {System.out.println("客户端已连接,开始和客户端交互...");socketChannel.configureBlocking(false);ByteBuffer readBuffer = ByteBuffer.allocate(1024);while (true) {if(socketChannel.read(readBuffer) > 0) {System.out.println("接收到客户端消息: " + new String(readBuffer.array(), "utf-8").trim());readBuffer.clear();}if (consoleReader.ready()) {ByteBuffer writeBuffer = ByteBuffer.wrap(consoleReader.readLine().getBytes());socketChannel.write(writeBuffer);writeBuffer.clear();}Thread.sleep(1000);}}}} catch (IOException e) {throw new RuntimeException(e);} catch (InterruptedException e) {throw new RuntimeException(e);}}/*** 改良:* 1、支持一个客户端对多个服务端* 缺点:* 1、cpu空转* 2、未使用selector多路复用器,其编程其实还是类似与BIO形式(服务端还是每个线程对应一个客户端)*/private static void server3() {try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));) {serverSocketChannel.socket().bind(new InetSocketAddress(9999));serverSocketChannel.configureBlocking(false);List<SocketChannel> socketChannels = new ArrayList<>();//accept设置了非阻塞,因此需要放置在循环中使用,否则程序直接结束了while (true) {Thread.sleep(1000);boolean ready = consoleReader.ready();byte[] bytes = null;if (ready) {bytes = consoleReader.readLine().getBytes();}//调用一次accept再次使用会变成成null,除非有新的客户端连接SocketChannel socketChannel = serverSocketChannel.accept();if (socketChannel != null) {socketChannels.add(socketChannel);socketChannel.configureBlocking(false);System.out.println("客户端已连接,开始和客户端交互...");}for (SocketChannel channel : socketChannels) {ByteBuffer readBuffer = ByteBuffer.allocate(1024);if (channel.read(readBuffer) > 0) {System.out.println("接收到客户端消息: " + new String(readBuffer.array(), "utf-8").trim());readBuffer.clear();}if (ready) {ByteBuffer writeBuffer = ByteBuffer.wrap(bytes);channel.write(writeBuffer);writeBuffer.clear();}}}} catch (IOException e) {throw new RuntimeException(e);} catch (InterruptedException e) {throw new RuntimeException(e);}}/*** 改良:* 1、支持一个客户端对多个服务端 (服务端发送消息,客户端都能收到,所有客户端发送消息服务端都能收到)* 2、相对与server3多线程方式,服务端只需要启动一个主线程即可与所有客户端交互,* 缺点:* 1、cpu空转* 2、未使用selector多路复用器,其编程其实还是类似与BIO形式(服务端还是每个线程对应一个客户端)*/static final List<SocketChannel> socketChannels4 = new CopyOnWriteArrayList<>();private static void server4() {try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));) {serverSocketChannel.socket().bind(new InetSocketAddress(9999));serverSocketChannel.configureBlocking(false);//accept设置了非阻塞,因此需要放置在循环中使用,否则程序直接结束了while (true) {SocketChannel socketChannel = serverSocketChannel.accept();if (socketChannel != null) {System.out.println("客户端已连接,开始和客户端交互...");socketChannel.configureBlocking(false);socketChannels4.add(socketChannel);}Iterator<SocketChannel> iterator = socketChannels4.iterator();boolean ready = consoleReader.ready();byte[] writeBytes = null;if (ready) {writeBytes = consoleReader.readLine().getBytes();}while (iterator.hasNext()) {ByteBuffer readBuffer = ByteBuffer.allocate(1024);SocketChannel channel = iterator.next();if (channel.read(readBuffer) > 0) {System.out.println("接收到客户端消息: " + new String(readBuffer.array(), "utf-8").trim());readBuffer.clear();}if (ready) {ByteBuffer writeBuffer = ByteBuffer.wrap(writeBytes);channel.write(writeBuffer);writeBuffer.clear();}}Thread.sleep(1000);}} catch (IOException | InterruptedException e) {throw new RuntimeException(e);}}/*** 改良:* 1、支持一个客户端对多个服务端 (服务端发送消息,客户端都能收到,所有客户端发送消息服务端都能收到)* 2、相对与server3多线程方式,服务端只需要启动一个主线程即可与所有客户端交互,* 缺点:* 1、cpu空转* 2、未使用selector多路复用器,其编程其实还是类似与BIO形式(服务端还是每个线程对应一个客户端)*/private static void server5() {try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();Selector selector = Selector.open();BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));) {serverSocketChannel.socket().bind(new InetSocketAddress(9999));serverSocketChannel.configureBlocking(false);//将serverSocketChannel注册到selector, 并监听accept事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);List<SocketChannel> socketChannels = new ArrayList<>();while (true) {//非阻塞selector.select(1000);Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()) {SelectionKey selectionKey = iterator.next();if(selectionKey.isAcceptable()) {SocketChannel socketChannel = serverSocketChannel.accept();System.out.println("客户端已连接,开始和客户端交互...");socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);socketChannels.add(socketChannel);} else if(selectionKey.isReadable()) {SocketChannel socketChannel = (SocketChannel)selectionKey.channel();ByteBuffer readBuffer = ByteBuffer.allocate(1024);if (socketChannel.read(readBuffer) > 0) {System.out.println("接收到客户端消息: " + new String(readBuffer.array(), "utf-8").trim());readBuffer.clear();}}iterator.remove();}if(consoleReader.ready()) {byte[] bytes = consoleReader.readLine().getBytes();for (SocketChannel socketChannel : socketChannels) {ByteBuffer writeBuffer = ByteBuffer.wrap(bytes);socketChannel.write(writeBuffer);writeBuffer.clear();}}}} catch (IOException e) {throw new RuntimeException(e);}}}

NIO Client

public class SocketClient {public static void main(String[] args) {//client1();//client2_3_4();client5();}private static void client1() {try (SocketChannel socketChannel = SocketChannel.open();){socketChannel.configureBlocking(false);socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));while (!socketChannel.finishConnect()) {Thread.sleep(1000);System.out.println("正在连接客户端...");}ByteBuffer writeBuffer = ByteBuffer.wrap("向服务端发送消息".getBytes());socketChannel.write(writeBuffer);writeBuffer.clear();ByteBuffer readBuffer = ByteBuffer.allocate(1024);while (true) {if(socketChannel.read(readBuffer) > 0) {System.out.println("接收到服务端消息: " + new String(readBuffer.array(), "utf-8").trim());readBuffer.clear();break;}Thread.sleep(1000);}} catch (IOException | InterruptedException e) {throw new RuntimeException(e);}}private static void client2_3_4() {try (SocketChannel socketChannel = SocketChannel.open();BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));){socketChannel.configureBlocking(false);socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));while (!socketChannel.finishConnect()) {Thread.sleep(1000);System.out.println("正在连接客户端...");}ByteBuffer readBuffer = ByteBuffer.allocate(1024);while (true) {if(socketChannel.read(readBuffer) > 0) {System.out.println("接收到服务端消息: " + new String(readBuffer.array(), "utf-8").trim());readBuffer.clear();}if (consoleReader.ready()) {ByteBuffer writeBuffer = ByteBuffer.wrap(consoleReader.readLine().getBytes());socketChannel.write(writeBuffer);writeBuffer.clear();}Thread.sleep(1000);}} catch (IOException | InterruptedException e) {throw new RuntimeException(e);}}private static void client5() {try (SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9999));Selector selector = Selector.open();BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));){socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);while (true) {selector.select(1000);Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()) {SelectionKey selectionKey = iterator.next();if (selectionKey.isReadable()) {SocketChannel channel = (SocketChannel) selectionKey.channel();ByteBuffer readBuffer = ByteBuffer.allocate(1024);if(channel.read(readBuffer) > 0) {System.out.println("接收到服务端消息: " + new String(readBuffer.array(), "utf-8").trim());readBuffer.clear();}}iterator.remove();}if (consoleReader.ready()){ByteBuffer writeBuffer = ByteBuffer.wrap(consoleReader.readLine().getBytes());socketChannel.write(writeBuffer);writeBuffer.clear();}}} catch (IOException e) {throw new RuntimeException(e);}}}

更多推荐

IO/NIO交互模拟及渐进式实现

本文发布于:2023-12-07 10:45:04,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1671031.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:渐进式   IO   NIO

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!