NIO简单实现
NIO三件套:Buffer:数据载体、channel:载体通道、Selector:选择器。
NIO三种状态:
如果无客户端请求连接,直到有客户端请求连接之前select()方法一直被阻塞状态。
如果有客户端请求连接,但是客户端连接的请求没有被处理,此时select()方法是非阻塞状态。
如果有客户端请求连接,客户端连接的请求被处理,此时select()方法是阻塞状态。
服务端
package com.sunny.service; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; import java.util.Set; public class SelectorServerSocketTest { // 模拟NIO 这里一个主线程可以处理三个客户端的请求 public static void main(String[] args) { try ( // 获取一个选择器 Selector selector = Selector.open(); // 获取多个ServerSocketChannel ServerSocketChannel serverSocketChannel6666 = ServerSocketChannel.open(); ServerSocketChannel serverSocketChannel7777 = ServerSocketChannel.open(); ServerSocketChannel serverSocketChannel8888 = ServerSocketChannel.open(); ) { serverSocketChannel6666.bind(new InetSocketAddress(6666)); serverSocketChannel7777.bind(new InetSocketAddress(7777)); serverSocketChannel8888.bind(new InetSocketAddress(8888)); // ServerSocketChannel默认是阻塞,因为要实现Selector同步非阻塞,因此现需要将serverSocketChannel6 设置成非阻塞 serverSocketChannel6666.configureBlocking(false); serverSocketChannel7777.configureBlocking(false); serverSocketChannel8888.configureBlocking(false); // 将多少ServerSocketChannel注册到一个选择器上 // 只能注册SelectionKey.OP_ACCEPT ,也就是接受就绪事件 serverSocketChannel6666.register(selector, SelectionKey.OP_ACCEPT); serverSocketChannel7777.register(selector, SelectionKey.OP_ACCEPT); serverSocketChannel8888.register(selector, SelectionKey.OP_ACCEPT); int registerChannelSize = selector.keys().size(); System.out.println("当前选择器上注册" + registerChannelSize + "个服务器管道"); int connectionChannelSize = selector.selectedKeys().size(); System.out.println("当前选择器上连接了" + connectionChannelSize + "个服务器管道"); //处理客户端请求 // 轮询访问selector while (true) { System.out.println("服务器:服务器开始等待客户端连接"); selector.select(); System.out.println("服务器:服务器已接受到客户端连接"); connectionChannelSize = selector.selectedKeys().size(); System.out.println("当前选择器上连接了" + connectionChannelSize + "个服务器管道"); Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> selectionKeysIterator = selectionKeys.iterator(); // 获得selector中选中的项的迭代器,选中的项为注册的事件 while (selectionKeysIterator.hasNext()) { SelectionKey selectionKey = selectionKeysIterator.next(); ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel(); SocketChannel socketChannel = serverSocketChannel.accept(); ByteBuffer clientRequestByteBuffer = ByteBuffer.allocate(1024); int clientRequestLength = socketChannel.read(clientRequestByteBuffer); String clientRequestDate = new String(clientRequestByteBuffer.array(), 0, clientRequestLength); System.out.println("服务器:客户端请求内容:" + clientRequestDate); // 根据不同请求响应不同结果 String responseDateByteRequestDate = getResponseDateByteRequestDate(clientRequestDate); ByteBuffer serverResponseByteBuffer = ByteBuffer.allocate(1024); serverResponseByteBuffer.put(responseDateByteRequestDate.getBytes()); serverResponseByteBuffer.flip(); socketChannel.write(serverResponseByteBuffer); System.out.println("服务器:服务器响应给客户端的是"+responseDateByteRequestDate); System.out.println(); // 处理完以后删除已处理的 selectionKeysIterator.remove(); } } } catch (IOException e) { e.printStackTrace(); } } private static String getResponseDateByteRequestDate(String requestDate) { String responstDate = null; if ("跟光磊学习Java怎么样".equals("跟光磊学习Java怎么样")) { responstDate = "很棒"; } else if ("跟光磊学习前段怎么样".equals("跟光磊学习前段怎么样")) { responstDate = "很好"; } else if ("跟光磊学习Linux怎么样".equals("跟光磊学习Linux怎么样")) { responstDate = "好吸收"; } return responstDate; } }
客户端
package com.sunny.service; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.HashMap; import java.util.Map; import java.util.Set; public class SelectorSocketTest { public static void main(String[] args) { Map<Integer, String> clientRequest = new HashMap<>(); clientRequest.put(6666,"跟光磊学习Java怎么样?"); clientRequest.put(7777,"跟光磊学习前段怎么样?"); clientRequest.put(8888,"跟光磊学习Linux怎么样?"); Set<Map.Entry<Integer, String>> clientRequestEntrySet = clientRequest.entrySet(); for (Map.Entry<Integer, String> integerStringEntry : clientRequestEntrySet) { Integer clientRequestPort = integerStringEntry.getKey(); String clientRequestDate = integerStringEntry.getValue(); try( SocketChannel socketChannel = SocketChannel.open(); ) { socketChannel.connect(new InetSocketAddress(clientRequestPort)); System.out.println("客户端:客户端连接服务器"+clientRequestPort); ByteBuffer clientRequestByteBuffer = ByteBuffer.allocate(1024); clientRequestByteBuffer.put(clientRequestDate.getBytes()); clientRequestByteBuffer.flip(); socketChannel.write(clientRequestByteBuffer); System.out.println("客户端:客户端发送请求给"+clientRequestPort+"的服务器,请求内容:"+clientRequestDate); // 接收客户端响应的信息 ByteBuffer serverByteBuffer = ByteBuffer.allocate(1024); int serverByteBufferLength = socketChannel.read(serverByteBuffer); String serverResponseDate = new String(serverByteBuffer.array(), 0, serverByteBufferLength); System.out.println("客户端:客户端接收服务器响应数据:"+serverResponseDate); } catch (IOException e) { e.printStackTrace(); } } } }