NIO的出现使得传统的Socket的通讯发生了巨大的改变。
NIO本质就是避免原始的TCP建立连接使用的3次握手的操作,减少网络开销。
NIO是非阻塞的
相比于传统的阻塞型IO,NIO是非阻塞的,所以对于服务端有如下做法:
/*使用NIO非阻塞处理socket请求*/
public static void s5() throws IOException {
ExecutorService threadPool = new ThreadPoolExecutor(10,50,60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(9999));
while (true){
System.out.println("等待客户端接入...");
SocketChannel socketChannel = serverSocketChannel.accept();
if(socketChannel==null){
continue;
}
threadPool.execute(()->{
try {
clientJoin();
read(socketChannel);
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
private static void read(SocketChannel socketChannel) throws IOException {
StringBuilder content = new StringBuilder();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
while(socketChannel.read(byteBuffer)!=-1){
byteBuffer.flip();
while (byteBuffer.hasRemaining()){
byte[] data = new byte[byteBuffer.remaining()];
byteBuffer.get(data);
content.append(new String(data,0,data.length));
}
byteBuffer.clear();
}
System.out.println(content.toString());
}
当然也可以使用著名的Reactoer模式
服务端
/*Reactor模型*/
public static void s6() throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(9999));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select()>0){
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
if (selectionKey.isConnectable()){
onConnection(selectionKey);
}else if(selectionKey.isAcceptable()){
onAccept(selectionKey);
}else if(selectionKey.isReadable()){
onRead(selectionKey);
}else if(selectionKey.isWritable()){
onWrite(selectionKey);
}
iterator.remove();
}
}
}
private static void onWrite(SelectionKey selectionKey) throws IOException {
System.out.println("写就绪");
SocketChannel channel = (SocketChannel) selectionKey.channel();
write(channel);
channel.close();
}
private static void onRead(SelectionKey selectionKey) throws IOException {
System.out.println("读就绪");
SocketChannel channel = (SocketChannel) selectionKey.channel();
read(channel);
channel.register(selectionKey.selector(),SelectionKey.OP_WRITE);
}
private static void onAccept(SelectionKey selectionKey) throws IOException {
System.out.println("接收数据就绪");
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
Selector selector = selectionKey.selector();
socketChannel.configureBlocking(false);
socketChannel.register(selector,SelectionKey.OP_READ);
}
private static void onConnection(SelectionKey selectionKey) {
System.out.println("链接就绪");
}
private static void read(SocketChannel socketChannel) throws IOException {
StringBuilder content = new StringBuilder();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
while(socketChannel.read(byteBuffer)!=-1){
byteBuffer.flip();
while (byteBuffer.hasRemaining()){
byte[] data = new byte[byteBuffer.remaining()];
byteBuffer.get(data);
content.append(new String(data,0,data.length));
}
byteBuffer.clear();
}
System.out.println(content.toString());
}
private static void write(SocketChannel socketChannel) throws IOException {
byte[] data = "这是服务端,正在使用Channel".getBytes();
ByteBuffer byteBuffer = ByteBuffer.allocate(data.length);
byteBuffer.put(data);
byteBuffer.flip();
socketChannel.write(byteBuffer);
}
网友评论