public class NioServer {
private static Selector selector;
public static void main(String[] args) throws IOException {
NioServer nioServer = new NioServer();
nioServer.initServer(8001);
nioServer.listen();
}
//获得一个通道并对该通道做一些初始化工作
public void initServer(int port) throws IOException {
//创建nio通道,获取一个seversocket
ServerSocketChannel channel = ServerSocketChannel.open();
//设置通道为非阻塞,设置true就有异常
channel.configureBlocking(false);
//设置基于nio的socket
ServerSocket serverSocket = channel.socket();
//新建socket通道的端口,将该通道对应的 serverSocket绑定到port
serverSocket.bind(new InetSocketAddress(port));
//获取通道管理器
selector = Selector.open();
//将设置的通道管理器和通道绑定,并注册SelectionKey.OP_ACCEPT事件
//当该事件到达的时候,selector.select()会返回果该事件没有到达selector.select()会阻塞
//将nio绑定到选择器。绑定后分配的主键为selectionKey
SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_ACCEPT);
}
/**
* 采用轮询的方式监听selector。是否需要处理事件,需要就进行处理
* 轮询:由cpu定时发出询问,依次询问每一个周边设备是否需要服务,有就给服务,服务结束后询问下一个
* @throws IOException
*/
public void listen() throws IOException {
System.out.println("服务器启动成功");
while (true) {
//当注册的事件到达时,方法返回,否则方法一直阻塞
//获取通道内是否有选择器的服务事件
int num = selector.select();
if (num<1) {
continue;
}
//获取通道服务时间的集合 ,一个是新顾客的事件,一个是老顾客
Set selectKey = selector.selectedKeys();
Iterator iterator = selectKey.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
//删除已经处理的事件,防止重复处理
iterator.remove();
handler(key);
}
}
}
//处理请求是老顾客还是新顾客
public void handler(SelectionKey key) throws IOException {
//判断是不是新的顾客,测试此密钥的通道是否追备好接受新的套接字连接
if (key.isAcceptable()) {
handlerAccept(key);
}else if(key.isReadable()){
handlerRead(key);
}
}
//处理连接事件
public void handlerAccept(SelectionKey key) throws IOException {
//新顾客新注册
ServerSocketChannel channel = (ServerSocketChannel) key.channel();
//获取客户端连接通道
SocketChannel socketChannel = channel.accept();
//将该通道设置成非阻塞,设置成true有异常
socketChannel.configureBlocking(false);
//可以给客户端发信息
System.out.println("这是新的客户端连接");
//在和客户端连接成功后,需要给通道设置权限
SelectionKey newkey = socketChannel.register(selector, SelectionKey.OP_READ);
}
//处理读的事件
public void handlerRead(SelectionKey key) throws IOException {
//服务器可读取客户端消息,得到时间发送的socket通道
SocketChannel socketChannel = (SocketChannel) key.channel();
//创建读取的缓冲区,一次能接受字节 ,相当于byte数组,存储读取数据
ByteBuffer buffer = ByteBuffer.allocate(1024);
//读取字节byte往buffer里面读
int read = socketChannel.read(buffer);
if (read>0) {
byte[] data = buffer.array();//把buffer变成字节数组
String mString = new String(data).trim();
System.out.println("服务器端收到的信息"+mString);
//回写数据,给客户端发送信息
ByteBuffer out = ByteBuffer.wrap("好的".getBytes());
//将信息写给客户端
socketChannel.write(out);
}else {
System.out.println("客户端关闭");
key.cancel();
}
}
}