Java NIO 通信
服务器端:
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; public class NIOServer { // 用于检测所有Channel状态的Selector private Selector selector = null; private static final int PORT = 30000; // 定义实现编码、解码的字符集对象 private Charset charset = Charset.forName("UTF-8"); public void init() throws Exception { selector = Selector.open(); // 通过open方法来打开一个未绑定的ServerSocketChannel实例 ServerSocketChannel server = ServerSocketChannel.open(); InetSocketAddress isa = new InetSocketAddress("127.0.0.1", PORT); // 将该ServerSocketChannel绑定到指定IP地址 server.bind(isa); // 设置ServerSocket以非阻塞方式工作 server.configureBlocking(false); // 将server注册到指定Selector对象 server.register(selector, SelectionKey.OP_ACCEPT); while (selector.select() > 0) { // 依次处理selector上的每个已选择的SelectionKey for (SelectionKey sk : selector.selectedKeys()) { // 从selector上的已选择Key集中删除正在处理的SelectionKey selector.selectedKeys().remove(sk); // 如果sk对应的Channel包含客户端的连接请求 if (sk.isAcceptable()) { // 调用accept方法接受连接,产生服务器端的SocketChannel SocketChannel sc = server.accept(); // 设置采用非阻塞模式 sc.configureBlocking(false); // 将该SocketChannel也注册到selector sc.register(selector, SelectionKey.OP_READ); // 将sk对应的Channel设置成准备接受其他请求 sk.interestOps(SelectionKey.OP_ACCEPT); } // 如果sk对应的Channel有数据需要读取 if (sk.isReadable()) { // 获取该SelectionKey对应的Channel,该Channel中有可读的数据 SocketChannel sc = (SocketChannel) sk.channel(); // 定义准备执行读取数据的ByteBuffer ByteBuffer buffer = ByteBuffer.allocate(1024); StringBuilder content = new StringBuilder(); // 开始读取数据 try { while (sc.read(buffer) > 0) { buffer.flip(); content.append(charset.decode(buffer)); } // 打印从该sk对应的Channel里读取到的数据 System.out.println("读取的数据:" + content); // 将sk对应的Channel设置成准备下一次读取 sk.interestOps(SelectionKey.OP_READ); } catch (IOException ex) { // 如果捕捉到该sk对应的Channel出现了异常,即表明该Channel对应的Client出现了问题,所以从Selector中取消sk的注册 // 从Selector中删除指定的SelectionKey sk.cancel(); if (sk.channel() != null) { sk.channel().close(); } } // 如果content的长度大于0,即聊天信息不为空 if (content.toString().length() > 0) { // 遍历该selector里注册的所有SelectionKey for (SelectionKey key : selector.keys()) { // 获取该key对应的Channel Channel targetChannel = key.channel(); // 如果该channel是SocketChannel对象 if (targetChannel instanceof SocketChannel) { // 将读到的内容写入该Channel中 SocketChannel dest = (SocketChannel) targetChannel; dest.write(charset.encode(content.toString())); } } } } } } } public static void main(String[] args) throws Exception { new NIOServer().init(); } }
客户端:
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.SocketChannel; import java.nio.charset.Charset; import java.util.Scanner; public class NIOClient { // 定义检测SocketChannel的Selector对象 private Selector selector = null; private static final int PORT = 30000; // 定义处理编码和解码的字符集 private Charset charset = Charset.forName("UTF-8"); // 客户端SocketChannel private SocketChannel sc = null; public void init() throws IOException { selector = Selector.open(); InetSocketAddress isa = new InetSocketAddress("127.0.0.1", PORT); // 调用open静态方法创建连接到指定主机的SocketChannel sc = SocketChannel.open(isa); // 设置该sc以非阻塞方式工作 sc.configureBlocking(false); // 将SocketChannel对象注册到指定Selector sc.register(selector, SelectionKey.OP_READ); // 启动读取服务器端数据的线程 new ClientThread().start(); // 创建键盘输入流 Scanner scan = new Scanner(System.in); while (scan.hasNextLine()) { // 读取键盘输入 String line = scan.nextLine(); // 将键盘输入的内容输出到SocketChannel中 sc.write(charset.encode(line)); } } // 定义读取服务器数据的线程 private class ClientThread extends Thread { @Override public void run() { try { while (selector.select() > 0) { // 遍历每个有可用IO操作Channel对应的SelectionKey for (SelectionKey sk : selector.keys()) { // 删除正在处理的SelectionKey selector.selectedKeys().remove(sk); // 如果该SelectionKey对应的Channel中有可读的数据 if (sk.isReadable()) { // 使用NIO读取Channel中的数据 SocketChannel sc = (SocketChannel) sk.channel(); ByteBuffer buff = ByteBuffer.allocate(1024); StringBuilder content = new StringBuilder(); while (sc.read(buff) > 0) { sc.read(buff); buff.flip(); content.append(charset.decode(buff)); } // 打印输出读取的内容 System.out.println("聊天信息:" + content.toString()); // 为下一次读取作准备 sk.interestOps(SelectionKey.OP_READ); } } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) throws IOException { new NIOClient().init(); } }
Java AIO 通信
服务器端
import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousChannelGroup; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class AIOServer { static final int PORT = 30000; final static String UTF_8 = "utf-8"; static List<AsynchronousSocketChannel> channelList = new ArrayList<>(); public void startListen() throws InterruptedException, Exception { // 创建一个线程池 ExecutorService executor = Executors.newFixedThreadPool(20); // 以指定线程池来创建一个AsynchronousChannelGroup AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup .withThreadPool(executor); // 以指定线程池来创建一个AsynchronousServerSocketChannel AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(channelGroup) // 指定监听本机的PORT端口 .bind(new InetSocketAddress(PORT)); // 使用CompletionHandler接受来自客户端的连接请求 serverChannel.accept(null, new AcceptHandler(serverChannel)); //① } public static void main(String[] args) throws Exception { AIOServer server = new AIOServer(); server.startListen(); } } // 实现自己的CompletionHandler类 class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, Object> { private AsynchronousServerSocketChannel serverChannel; public AcceptHandler(AsynchronousServerSocketChannel sc) { this.serverChannel = sc; } // 定义一个ByteBuffer准备读取数据 ByteBuffer buff = ByteBuffer.allocate(1024); // 当实际IO操作完成时候触发该方法 @Override public void completed(final AsynchronousSocketChannel sc , Object attachment) { // 记录新连接的进来的Channel AIOServer.channelList.add(sc); // 准备接受客户端的下一次连接 serverChannel.accept(null , this); sc.read(buff , null , new CompletionHandler<Integer,Object>() //② { @Override public void completed(Integer result , Object attachment) { buff.flip(); // 将buff中内容转换为字符串 String content = StandardCharsets.UTF_8 .decode(buff).toString(); // 遍历每个Channel,将收到的信息写入各Channel中 for(AsynchronousSocketChannel c : AIOServer.channelList) { try { c.write(ByteBuffer.wrap(content.getBytes( AIOServer.UTF_8))).get(); } catch (Exception ex) { ex.printStackTrace(); } } buff.clear(); // 读取下一次数据 sc.read(buff , null , this); } @Override public void failed(Throwable ex, Object attachment) { System.out.println("读取数据失败: " + ex); // 从该Channel读取数据失败,就将该Channel删除 AIOServer.channelList.remove(sc); } }); } @Override public void failed(Throwable ex, Object attachment) { System.out.println("连接失败: " + ex); } }
客户端:
import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousChannelGroup; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.nio.charset.StandardCharsets; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.KeyStroke; public class AIOClient { final static String UTF_8 = "utf-8"; final static int PORT = 30000; // 与服务器端通信的异步Channel AsynchronousSocketChannel clientChannel; JFrame mainWin = new JFrame("多人聊天"); JTextArea jta = new JTextArea(16, 48); JTextField jtf = new JTextField(40); JButton sendBn = new JButton("发送"); public void init() { mainWin.setLayout(new BorderLayout()); jta.setEditable(false); mainWin.add(new JScrollPane(jta), BorderLayout.CENTER); JPanel jp = new JPanel(); jp.add(jtf); jp.add(sendBn); // 发送消息的Action,Action是ActionListener的子接口 Action sendAction = new AbstractAction() { public void actionPerformed(ActionEvent e) { String content = jtf.getText(); if (content.trim().length() > 0) { try { // 将content内容写入Channel中 clientChannel.write(ByteBuffer.wrap(content.trim().getBytes(UTF_8))).get(); // ① } catch (Exception ex) { ex.printStackTrace(); } } // 清空输入框 jtf.setText(""); } }; sendBn.addActionListener(sendAction); // 将Ctrl+Enter键和"send"关联 jtf.getInputMap().put(KeyStroke.getKeyStroke('\n', java.awt.event.InputEvent.CTRL_MASK), "send"); // 将"send"和sendAction关联 jtf.getActionMap().put("send", sendAction); mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainWin.add(jp, BorderLayout.SOUTH); mainWin.pack(); mainWin.setVisible(true); } public void connect() throws Exception { // 定义一个ByteBuffer准备读取数据 final ByteBuffer buff = ByteBuffer.allocate(1024); // 创建一个线程池 ExecutorService executor = Executors.newFixedThreadPool(80); // 以指定线程池来创建一个AsynchronousChannelGroup AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executor); // 以channelGroup作为组管理器来创建AsynchronousSocketChannel clientChannel = AsynchronousSocketChannel.open(channelGroup); // 让AsynchronousSocketChannel连接到指定IP、指定端口 clientChannel.connect(new InetSocketAddress("127.0.0.1", PORT)).get(); jta.append("---与服务器连接成功---\n"); buff.clear(); clientChannel.read(buff, null, new CompletionHandler<Integer, Object>() // ② { @Override public void completed(Integer result, Object attachment) { buff.flip(); // 将buff中内容转换为字符串 String content = StandardCharsets.UTF_8.decode(buff).toString(); // 显示从服务器端读取的数据 jta.append("某人说:" + content + "\n"); buff.clear(); clientChannel.read(buff, null, this); } @Override public void failed(Throwable ex, Object attachment) { System.out.println("读取数据失败: " + ex); } }); } public static void main(String[] args) throws Exception { AIOClient client = new AIOClient(); client.init(); client.connect(); } }
相关推荐
全面理解 Java 网络编程 - BIO、NIO、AIO 本课程旨在帮助学生全面理解 Java 网络编程中的 BIO、NIO、AIO 三剑客,掌握 RPC 编程的基础知识,并结合实战项目巩固所学。 一、网络编程三剑客 - BIO、NIO、AIO BIO...
Java作为一门广泛使用的开发语言,提供了多种I/O(Input/Output)通信模型,包括传统的阻塞I/O(BIO)、非阻塞I/O(NIO)以及异步I/O(AIO)。这些通信模型在不同的场景下有着各自的优势,理解和掌握它们对于优化...
为了处理与外部世界的交互,Java提供了三种不同的I/O模型:BIO( Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)。这些模型各有优缺点,适用于不同场景。下面我们将深入探讨这三种I/O模型,并...
Java BIO NIO AIO Java BIO、NIO、AIO是 Java 中的三种 I/O 模式,每种模式都有其特点和应用场景。下面对每种模式进行详细解释。 Java BIO Java BIO( Blocking I/O)是一种同步阻塞式的 I/O 模式,即服务器实现...
鹊桥,又称为MagpieBridge,是一款基于Java的内网穿透工具,利用先进的异步I/O模型(AIO/NIO)来实现高效的网络通信。它为开发者提供了在内网环境中进行开发并允许外部进行调试的强大功能,对于远程协作、云服务测试...
Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码) Java 网络IO编程是 Java 编程语言中最重要的知识点之一,涉及到网络编程的各种技术和模型。本篇文章主要介绍了 Java 网络IO编程总结,包括 BIO、NIO 和 AIO ...
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统I/O模型的新技术。尚硅谷的12讲Java NIO课程,旨在深入浅出地讲解这一重要概念,帮助开发者提升程序的性能和效率。...
【Java 高并发八:NIO和AIO详解】 NIO(New Input/Output),从Java 1.4版本开始引入,是对传统IO模型的一种改进。传统的IO模型基于流(Stream),而NIO则基于块(Block)进行数据传输,提高了处理大量数据时的效率...
Java网络通信中,AIO(Asynchronous Input/Output)、BIO(Blocking I/O)和NIO(Non-blocking I/O)是三种不同的I/O模型,它们各自有着不同的特性和适用场景。下面将详细介绍这三个概念以及它们在Java中的实现。 *...
本教程将围绕“高性能的Java AIO通信框架”这一主题,结合物联网应用需求,探讨相关知识点。 首先,AIO的核心在于其非阻塞特性。传统的Java IO基于BIO模型,当进行读写操作时,会阻塞线程,直到数据传输完成。而AIO...
SocketIO-BIO-NIO-AIO.zip是一个压缩包文件,它包含了一个关于Java中三种不同的I/O模型——BIO( Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)的深入讲解。这些I/O模型是Java进行网络编程时的...
9. **性能优化**:为了提高服务器的并发处理能力,可能需要用到NIO(非阻塞I/O)或AIO(异步I/O),这些API能更好地处理大量并发连接,减少线程的创建和管理成本。 10. **安全性**:在网络通信中,安全性至关重要。...
《Java IO:从NIO到Reactor三种模式详解》 在Java编程中,IO操作是不可或缺的一部分,尤其在处理大量数据传输或者网络通信时。本文将深入探讨Java中的三种IO模型:传统IO(BIO)、非阻塞IO(NIO)以及反应器模式...
在Netty中,使用NIO或AIO实现的TCP连接,可以结合其线程模型,如EventLoopGroup(事件循环组)和ChannelHandler(通道处理器)等组件,实现高效、可扩展的网络通信。例如,BossGroup处理新的连接请求,WorkerGroup...
### 2024年Java常见BIO、NIO、AIO、Netty面试题解析 #### 一、基础知识概述 1. **IO概念**: - Java中的I/O(Input/Output)指的是输入输出操作,它以流为基础进行数据的输入输出。所有的数据在Java中都是以流的...
Java平台提供了多种I/O模型来支持网络通信,包括传统的阻塞I/O(BIO)、非阻塞I/O(NIO)以及异步I/O(AIO)。Netty是一个高性能、异步事件驱动的网络应用框架,它基于NIO进行优化,同时也实现了AIO特性。下面将分别...
### BIO、NIO、AIO、Netty 面试题解析 #### 1. Java IO 基础概述 Java中的I/O操作是通过流(Stream)来实现的,所有的数据都通过流的方式被串行化处理。串行化的含义在于数据必须按顺序输入输出。Java中的IO操作...