今天脑袋里突然冒出来NIO 所以记录一下
定义:什么是NIO 即 NOBLOCKING IO 与IO 有相同作用与目的 关于什么是IO本文不作解释
IO是以流的方式处理数据 NIO是以块的方式处理数据
关键: Buffer Channel Selector 简介
Buffer:包含了写入或读出的数据 在NIO中 数据是放在Buffer对象中的,程序不能直接对数据进行操作必须用buffer来进行操作。也就是说 Channel 通过buffer来读写数据。
Channel :可以通过Channel 读取和写入数据,类似流,但是与流不同的是 Channel 是双向的既能读又能写 还可以进行异步的读写 对Channel的读写必须通过buffer对象。
Selector:可以注册到多个Channel 上,监听各个Channel 发生的事件,根据事件定义情况决定Channel 读写
写了个步骤简单例子:
/**
* 服务器端
* */
public class NioSrver {
public void start() throws IOException {
/**
* 1.创建seletor
* */
Selector selector = Selector.open();
/**
* 2.通过serversocketChannel创建channel通道
* */
ServerSocketChannel channel = ServerSocketChannel.open();
/**
* 3.为channel绑定监听端口
* */
channel.bind(new InetSocketAddress(9876));
/**
* 4.设置channel为非阻塞模式
* */
channel.configureBlocking(false);
/**
* 5.将channel注册到selector上 监听连接事件
* */
channel.register(selector, SelectionKey.OP_ACCEPT);
/**
* 6.循环等待新接入连接
* */
for (;;) {
// 获取可用channel数量
int readychannels = selector.select();
// 没有可用channel数量跳出
if (readychannels == 0)
continue;
// 获取可用channel集合
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
/**
* 7.根据就绪状态 调用对应方法处理业务逻辑
* */
// 如果是接入事件
if (key.isAcceptable()) {
acceptHandler(channel, selector);
}
// 如果是可读事件
if (key.isReadable()) {
readHandler(key, selector);
}
}
}
}
/**
* 接入事件处理器
* */
private void acceptHandler(ServerSocketChannel serverSocketChannel,
Selector selector) throws IOException {
// 如果是接入事件 创建socketChannel
SocketChannel socketChannel = serverSocketChannel.accept();
// 将socketChannel设为非阻塞模式
socketChannel.configureBlocking(false);
// 将socketChannel注册到selector上 监听可读事件
socketChannel.register(selector, SelectionKey.OP_READ);
// 回复客户端信息
socketChannel.write(Charset.forName("utf-8").encode("连接成功"));
}
/**
* 可读事件处理器
* */
private void readHandler(SelectionKey selectionKey, Selector selector)
throws IOException {
// 从SelectionKey中 获取到已经就绪的channel 当前要处理的channel
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
// 创建buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// 循环客户端请求
String request = "";
while (socketChannel.read(byteBuffer) > 0) {
// 切换byteBuffer为读模式
byteBuffer.flip();
// 读取byteBuffer中的内容
request += Charset.forName("UTF-8").decode(byteBuffer);
}
// 再次将channel注册到selector上
socketChannel.register(selector, selectionKey.OP_READ);
// 将客户端发送的请求信息 广播给其他客户端
if (request.length() > 0) {
/*brodCast(selector, socketChannel, request);*/
System.out.println("-----");
}
}
/**
* 广播给其他客户端
*/
private void brodCast(Selector selector,SocketChannel socketChannel
,String request)throws IOException{
//获取所有已经接入的客户端channel
Set<SelectionKey>selectionKeySet = selector.keys();
//循环向channel广播信息
for (SelectionKey selectionKey : selectionKeySet) {
Channel targetChannel = selectionKey.channel();
if(targetChannel instanceof SocketChannel
&& targetChannel!=socketChannel){
((SocketChannel)targetChannel).write(Charset.forName("UTF-8").encode(request));
}
}
}
public static void main(String[] args) {
try {
new NioSrver().start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* NIO客户端
* */
public class NioClient {
/**
* 启动
* */
public void start(String name) throws IOException {
/**
* 连接服务器端
* */
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(
"127.0.0.1", 9876));
/**
* 接收服务端响应
* */
// 新建线程 专门负责接收服务器端的相应数据
Selector selector = Selector.open();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
new Thread(new NioClientHandler(selector)).start();
/**
* 向服务器发送数据
* */
Scanner sc = new Scanner(System.in);
String request = sc.nextLine();
while (sc.hasNextLine()) {
if (request != null && request.length() > 0) {
socketChannel.write(Charset.forName("UTF-8").encode(name+":"+request));
}
}
}
}
/**
* 客户端线程类 专门负责接收服务器端响应信息
* */
public class NioClientHandler implements Runnable {
private Selector selector;
public NioClientHandler(Selector selector) {
this.selector = selector;
}
@Override
public void run() {
try {
// TODO Auto-generated method stub
for (;;) {
// 获取可用channel数量
int readychannels = selector.select();
// 没有可用channel数量跳出
if (readychannels == 0)
continue;
// 获取可用channel集合
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
/**
* 7.根据就绪状态 调用对应方法处理业务逻辑
* */
// 如果是可读事件
if (key.isReadable()) {
readHandler(key, selector);
}
}
}
} catch (IOException e) {
}
}
/**
* 可读事件处理器
* */
private void readHandler(SelectionKey selectionKey, Selector selector)
throws IOException {
// 从SelectionKey中 获取到已经就绪的channel 当前要处理的channel
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
// 创建buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// 循环服务器端响应信息
String response = "";
while (socketChannel.read(byteBuffer) > 0) {
// 切换byteBuffer为读模式
byteBuffer.flip();
// 读取byteBuffer中的内容
response += Charset.forName("UTF-8").decode(byteBuffer);
}
// 再次将channel注册到selector上
socketChannel.register(selector, selectionKey.OP_READ);
// 将服务端响应信息打印到本地
if (response.length() > 0) {
System.out.println(response);
}
}
}
public class ClientA {
public static void main(String[] args)throws IOException{
new NioClient().start("腿腿");
}
}
public class ClientB {
public static void main(String[] args)throws IOException{
new NioClient().start("球球");
}
}
public class ClientC {
public static void main(String[] args)throws IOException{
new NioClient().start("蘑菇头");
}
}
就这样吧 记录一下 主要是记录使用步骤 按照1-7的步骤去做便于记忆。就酱。