服务端实现:
public static void main(String[] args) {
int port = 7236;
//NIO多路复用
//创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4, 4, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
threadPool.execute(new Runnable() {
@Override
public void run() {
try (Selector selector = Selector.open();
//ServerSocketChannel构造方法使用Protected进行修饰的
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
//绑定服务
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), port));
/* 设置 SocketChannel 为非阻塞模式
设置之后,就可以在异步模式下调用connect(), read() 和write()了
*/
serverSocketChannel.configureBlocking(false);
//
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();//阻塞等待就绪的Channel
//
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
try (SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();) {
channel.write(Charset.defaultCharset().encode("你好,世界-zzd"));
}
iterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
客户端实现:
public static void main(String[] args) {
int port = 7236;
//Socket客户端(接收信息并打印)
try(Socket socket = new Socket(InetAddress.getLocalHost(), port)){
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
reader.lines().forEach(s-> System.out.println("客户端:" + s));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
调用过程讲解:
- 首先,通过Selector.open()创建一个Selector,作为类似调度员的角色
- 然后,创建一个ServerSocketChannel,并且向Selector注册,通过指定SelectionKey.OP_ACCEPT,告诉调度员,它关注的是新建立的连接请求
- 为甚我们要明确配置非阻塞模式?这是因为阻塞模式下,注册操作是不允许的,会抛出IllegalBlockingModeException异常
- Selector阻塞在select操作,当有Channel发生接入请求,就会被唤醒