Java 非阻塞 socket 是一种网络通信技术,它可以让应用程序在不阻塞其他进程的情况下进行数据传输。它是一种异步的方式,可以在不同的进程之间传输数据,而不会影响其他进程的执行。
Java 非阻塞 socket 的工作原理是:当一个 socket 连接请求到达时,它将立即返回一个“已准备就绪”信号,而不是将请求阻塞住,直到有数据可用。当有数据可用时,socket 将通知应用程序并将数据传递出去。
SocketChannel channel = SocketChannel.open(); // 打开 SocketChannel channel.configureBlocking(false); // 设置为非阻塞 channel.connect(new InetSocketAddress("example.com", 80)); // 连接到 example.com 端口 80 while (!channel.finishConnect()) { // 如果还在连接中 // 做其他事情 } // 已完成连接
使用非阻塞套接字通道,我们必须改变我们对执行顺序的思考方式。
要创建选择器对象,请调用其open()静态方法。
Selector selector = Selector.open();
ServerSocketChannel用于监听来自客户端的新连接请求。
调用其open()静态方法来创建一个ServerSocketChannel。
ServerSocketChannel ssChannel = ServerSocketChannel.open();
默认情况下,服务器套接字通道或套接字通道是阻塞通道。要使其成为非阻塞通道,请调用以下方法。
ssChannel.configureBlocking(false);
服务器套接字必须向选择器注册才能执行某些操作。
有四种操作,我们可以用选择器注册一个通道。
以下代码显示如何创建非阻塞套接字通道回显服务器程序。
import java.net.InetAddress; 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.Iterator; import java.util.Set; public class Main { public static void main(String[] args) throws Exception { InetAddress hostIPAddress = InetAddress.getByName("localhost"); int port = 19000; Selector selector = Selector.open(); ServerSocketChannel ssChannel = ServerSocketChannel.open(); ssChannel.configureBlocking(false); ssChannel.socket().bind(new InetSocketAddress(hostIPAddress, port)); ssChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { if (selector.select() <= 0) { continue; } processReadySet(selector.selectedKeys()); } } public static void processReadySet(Set readySet) throws Exception { Iterator iterator = readySet.iterator(); while (iterator.hasNext()) { SelectionKey key = (SelectionKey) iterator.next(); iterator.remove(); if (key.isAcceptable()) { ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel(); SocketChannel sChannel = (SocketChannel) ssChannel.accept(); sChannel.configureBlocking(false); sChannel.register(key.selector(), SelectionKey.OP_READ); } if (key.isReadable()) { String msg = processRead(key); if (msg.length() > 0) { SocketChannel sChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes()); sChannel.write(buffer); } } } } public static String processRead(SelectionKey key) throws Exception { SocketChannel sChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesCount = sChannel.read(buffer); if (bytesCount > 0) { buffer.flip(); return new String(buffer.array()); } return "NoMessage"; } }
非阻塞套接字通道回显客户端程序
import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.Iterator; import java.util.Set; public class Main { static BufferedReader userInputReader = null; public static boolean processReadySet(Set readySet) throws Exception { Iterator iterator = readySet.iterator(); while (iterator.hasNext()) { SelectionKey key = (SelectionKey) iterator.next(); iterator.remove(); if (key.isConnectable()) { boolean connected = processConnect(key); if (!connected) { return true; // Exit } } if (key.isReadable()) { String msg = processRead(key); System.out.println("[Server]: " + msg); } if (key.isWritable()) { System.out.print("Please enter a message(Bye to quit):"); String msg = userInputReader.readLine(); if (msg.equalsIgnoreCase("bye")) { return true; // Exit } SocketChannel sChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes()); sChannel.write(buffer); } } return false; // Not done yet } public static boolean processConnect(SelectionKey key) throws Exception{ SocketChannel channel = (SocketChannel) key.channel(); while (channel.isConnectionPending()) { channel.finishConnect(); } return true; } public static String processRead(SelectionKey key) throws Exception { SocketChannel sChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); sChannel.read(buffer); buffer.flip(); Charset charset = Charset.forName("UTF-8"); CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer = decoder.decode(buffer); String msg = charBuffer.toString(); return msg; } public static void main(String[] args) throws Exception { InetAddress serverIPAddress = InetAddress.getByName("localhost"); int port = 19000; InetSocketAddress serverAddress = new InetSocketAddress( serverIPAddress, port); Selector selector = Selector.open(); SocketChannel channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(serverAddress); int operations = SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE; channel.register(selector, operations); userInputReader = new BufferedReader(new InputStreamReader(System.in)); while (true) { if (selector.select() > 0) { boolean doneStatus = processReadySet(selector.selectedKeys()); if (doneStatus) { break; } } } channel.close(); } }
Java ByteArrayOutputStream类字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中...
JSF教程 -JSF Facelets模板示例以下代码显示了如何使用JSF Facelets标签创建模板。JSF应用程序中的模板定义了公共接口布局和样式...
JSF教程 -JSF表单文本框示例h:inputText标签渲染类型为“text"的HTML输入元素。以下JSF标记h:inputText value="Hello World!" /...
JPA教程 - JPA一对多映射示例以下代码显示了如何在JPA中执行一对多映射。部门可以有一个或多个员工。在Java代码中,我们可以创建...
Java 实例 - 读取文件内容 Java 实例以下实例演示了使用 readLine() 方法来读取文件 test.log 内容,其中 test.log 文件内容为:...