服务器:
我们通过调用静态open方法创建Selector对象。然后,我们还通过调用其静态open方法(特别是ServerSocketChannel实例)来创建通道。
这是因为ServerSocketChannel是可选择的,并且适合于面向流的侦听套接字。
然后将其绑定到我们选择的端口。记得我们前面说过,在将可选通道注册到选择器之前,必须首先将其设置为非阻塞模式。接下来我们做这个,然后把通道注册到选择器。
Java NIO使用面向缓冲区的模型,而不是面向流的模型。所以套接字通信通常是通过读写缓冲区来进行的。
因此,我们创建一个新的ByteBuffer,服务器将从这个ByteBuffer写入和读取数据。我们将它初始化为256字节,它只是一个任意值,取决于我们计划来回传输多少数据。
ServerSocketChannel只能处理ACCEPT操作。当我们接受来自客户机的连接时,我们获得一个SocketChannel对象,我们可以在该对象上执行读写操作。我们将其设置为非阻塞模式,并将其注册为读取操作。
当我们想要写入正在从中读取的缓冲区时,必须调用flip()方法。
package nio.net_demo;
import java.io.File;
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.Iterator;
import java.util.Set;
public class NIOServer {
private static final String POISON_PILL = "POISON_PILL";
public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress("localhost", 5454));
serverSocket.configureBlocking(false);
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
ByteBuffer buffer = ByteBuffer.allocate(256);
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
register(selector, serverSocket);
}
if (key.isReadable()) {
answerWithEcho(buffer, key);
}
iter.remove();
}
}
}
private static void answerWithEcho(ByteBuffer buffer, SelectionKey key)
throws IOException {
SocketChannel client = (SocketChannel) key.channel();
client.read(buffer);
if (new String(buffer.array()).trim().equals(POISON_PILL)) {
client.close();
System.out.println("Not accepting client messages anymore");
}
buffer.flip();
client.write(buffer);
buffer.clear();
}
private static void register(Selector selector, ServerSocketChannel serverSocket)
throws IOException {
SocketChannel client = serverSocket.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
}
public static Process start() throws IOException, InterruptedException {
String javaHome = System.getProperty("java.home");
String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
String classpath = System.getProperty("java.class.path");
String className = NIOServer.class.getCanonicalName();
ProcessBuilder builder = new ProcessBuilder(javaBin, "-cp", classpath, className);
return builder.start();
}
}
客户端:我们使用一个单例模式在start静态方法中实例化它。我们从这个方法调用私有构造函数。在私有构造函数中,我们在绑定服务器通道的同一端口上打开连接,并且仍然在同一主机上。然后,我们创建一个可以写入和读取的缓冲区。最后,我们有一个sendMessage方法,它读取将传递给它的任何字符串包装到字节缓冲区中,字节缓冲区通过通道传输到服务器。
然后从客户端通道读取,以获取服务器发送的消息。
package nio.net_demo;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class NIOClient {
private static SocketChannel client;
private static ByteBuffer buffer;
private static NIOClient instance;
public static NIOClient start() {
if (instance == null)
instance = new NIOClient();
return instance;
}
public static void stop() throws IOException {
client.close();
buffer = null;
}
private NIOClient() {
try {
client = SocketChannel.open(new InetSocketAddress("localhost", 5454));
buffer = ByteBuffer.allocate(256);
} catch (IOException e) {
e.printStackTrace();
}
}
public String sendMessage(String msg) {
buffer = ByteBuffer.wrap(msg.getBytes());
String response = null;
try {
client.write(buffer);
buffer.clear();
client.read(buffer);
response = new String(buffer.array()).trim();
System.out.println("response=" + response);
buffer.clear();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
}
测试代码:
package nio.net_demo;
import java.io.IOException;
public class MianTest {
public static void main(String[] args) throws IOException, InterruptedException {
Process nioServer = NIOServer.start();
NIOClient nioClient = NIOClient.start();
nioClient.sendMessage("2323232424");
// nioServer.
}
}


本文介绍如何使用Java NIO创建服务器与客户端,通过ServerSocketChannel和SocketChannel进行非阻塞模式的通信,实现数据的接收与回传。文章详细讲解了选择器(Selector)的使用,以及如何在服务器端处理客户端连接请求,并通过ByteBuffer进行数据的读写。

799

被折叠的 条评论
为什么被折叠?



