一、建立Client端
package com.nio.selector.selector;
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.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class Client {
public static void main(String[] args) throws IOException {
// 创建客户端的通道
SocketChannel sc = SocketChannel.open();
// 获取选择器
Selector selc = Selector.open();
// 选择器管理的连接要求必须是非阻塞的
sc.configureBlocking(false);
// 将客户端注册到选择器身上,并且申请了一个可连接事件
sc.register(selc, SelectionKey.OP_CONNECT);
// 发起连接
sc.connect(new InetSocketAddress("localhost", 8090));
// 从这儿开始的代码针对多客户端来进行操作的
while (true) {
// 选择出注册过的通道
selc.select();
// 针对通道的不同事件类型进行处理
Set<SelectionKey> keys = selc.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
// 根据事件类型进行处理
SelectionKey key = it.next();
// 判断是否是可连接事件
if (key.isConnectable()) {
// 从当前事件中获取到对应的通道
SocketChannel scx = (SocketChannel) key.channel();
// 如果是可连接事件,判断连接是否成功
while (!scx.finishConnect())
;
// 如果连接成功了,可能会向服务器端发数据或者读数据
scx.register(selc, SelectionKey.OP_WRITE | SelectionKey.OP_READ);
}
// 判断是否是可写事件
if (key.isWritable()) {
// 从当前事件中获取到对应的通道
SocketChannel scx = (SocketChannel) key.channel();
// 写出数据
scx.write(ByteBuffer.wrap("hello~~~".getBytes()));
// 需要去掉可写事件
// 获取这个通道身上的所有的事件
scx.register(selc, key.interestOps() ^ SelectionKey.OP_WRITE);
}
// 判断是否是可读事件
if (key.isReadable()) {
// 从当前事件中来获取到对应的通道
SocketChannel scx = (SocketChannel) key.channel();
// 读取数据
ByteBuffer buffer = ByteBuffer.allocate(1024);
scx.read(buffer);
buffer.flip();
System.out.println(new String(buffer.array(), 0, buffer.limit()));
// 需要去掉这个可读事件
scx.register(selc, key.interestOps() ^ SelectionKey.OP_READ);
}
// 处理完这一大类事件之后
it.remove();
}
}
}
}
二、建立Server端
package com.nio.selector.selector;
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 Server {
public static void main(String[] args) throws IOException {
// 创建服务器端的通道
ServerSocketChannel ssc = ServerSocketChannel.open();
// 绑定要监听的端口号
ssc.bind(new InetSocketAddress(8090));
// 开启选择器
Selector selc = Selector.open();
ssc.configureBlocking(false);
// 将通道注册到选择器上,需要注册一个可接受事件
ssc.register(selc, SelectionKey.OP_ACCEPT);
while(true){
// 选择出已经注册的连接
selc.select();
// 根据事件的不同进行分别的处理
Set<SelectionKey> keys = selc.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
// 将事件取出来分别进行处理
SelectionKey key = it.next();
// 判断可接受事件
if(key.isAcceptable()){
// 从事件中获取到对应的通道
ServerSocketChannel sscx = (ServerSocketChannel) key.channel();
// 接受连接
SocketChannel sc = sscx.accept();
sc.configureBlocking(false);
// 注册读写事件
sc.register(selc, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
// 判断可读事件
if(key.isReadable()){
// 从事件中获取到对应的通道
SocketChannel sc = (SocketChannel) key.channel();
// 读取数据
ByteBuffer buffer = ByteBuffer.allocate(1024);
sc.read(buffer);
buffer.flip();
System.out.println(new String(buffer.array(),0, buffer.limit()));
// 需要去掉可读事件
sc.register(selc, key.interestOps() ^ SelectionKey.OP_READ);
}
// 判断可写事件
if(key.isWritable()){
// 从事件中获取到对应的通道
SocketChannel sc = (SocketChannel) key.channel();
// 写出数据
sc.write(ByteBuffer.wrap("收到".getBytes()));
// 需要去掉可写事件
sc.register(selc, key.interestOps() ^ SelectionKey.OP_WRITE);
}
// 去掉这一大类的事件
it.remove();
}
}
}
}