您的位置:首页 > 编程语言 > Java开发

JAVA NIO 的理解学习

2016-08-16 00:00 309 查看
java nio 基于事件机制监听 不同的channel 的动作从而做出相应的响应。响应线程无需像传统io阻塞等待响应。主要涉及到的是 Buffer,Channel 以及Selector

其中 Buffer 是缓冲器,数据的读写都必须从channel 经过buffer 获取或者写入channel中。

Channel 基于Nio 必须是无阻塞的 每一个客户端和服务端连接都回在服务端新建一个socketChannel,并通过 channel.register(selector,eventKey) 注册到Selector.selector 可以单线程 阻塞监听是否有事件发生,如果存在 调用事件注册的 服务进行相应的处理。

核心在于Selector。

以下是写的测试类:

package com.hrd.nio;

import java.io.IOException;
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.UUID;

/**
* 服务端和客户端 分别启动一个SelectorThread 用于监听事件,这里由于本机写成一个。
* @author hurd@omeng.cc
* @version v0.1
* @date 2016/8/16
* @desc TODO
* @see
*/
public class SelectThread extends Thread {

private String threadName;
private Selector selector;

public SelectThread(String threadName, Selector selector){
this.threadName = threadName;
this.selector = selector;
}

@Override
public void run() {

Thread.currentThread().setName(threadName);

try {
while(true){
//阻塞
selector.select();
//获取选择器中已经就绪的SelectionKey集合
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
//遍历
while (iterator.hasNext()){
SelectionKey key = iterator.next();
//删除
iterator.remove();
//接受连接就绪事件
if(key.isAcceptable()){
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = ssc.accept();
//套接字通道设置为非阻塞模式
socketChannel.configureBlocking(false);
//向socket通道 注册读就绪事件
socketChannel.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){
//SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
((SocketChannel)key.channel()).read(byteBuffer);
//将写模式变为读模式
byteBuffer.flip();
//读取完毕
if(byteBuffer.limit()>0){
System.out.println("线程:"+Thread.currentThread().getName()+"消息:" + new String(byteBuffer.array()).trim());
}
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
}else if(key.isWritable()){
//暂时还没想明白这个写就绪事件干嘛用的。。。
System.out.println("写就绪事件触发了,线程名:"+Thread.currentThread().getName());
ByteBuffer byteBuffer = ByteBuffer.allocate(1000);
byteBuffer.put((Thread.currentThread().getName() + UUID.randomUUID().toString()).getBytes());
SocketChannel socketChannel = (SocketChannel) key.channel();
byteBuffer.flip();
socketChannel.write(byteBuffer);
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
}else if(key.isConnectable()){
SocketChannel socketChannel = (SocketChannel) key.channel();
//判断连接是否完成
int i =0;
while(! socketChannel.finishConnect()){
if(++i>10){
throw  new RuntimeException("socket连接超时");
}
System.out.println("sock连接未完成,等待中....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//向socket通道 注册读就绪事件
socketChannel.register(selector, SelectionKey.OP_READ);
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
byteBuffer.put((Thread.currentThread().getName()+"客户端完成连接啦,感谢服务端哈").getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}

package com.hrd.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;

/**
* @author hurd@omeng.cc
* @version v0.1
* @date 2016/8/16
* @desc TODO
* @see
*/
public class ServerSocketMain {

public static void main(String[] args) throws IOException, InterruptedException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);

//绑定 ip 地址
serverSocketChannel.bind(new InetSocketAddress(8888));
//注册感兴趣的事件 这里注册 注册accept 和读就绪事件
Selector selector = Selector.open();
SelectThread threadThread = new SelectThread("server side",selector);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
//服务端阻塞监听selector 事件
threadThread.start();
serverSocketChannel.accept();

System.out.println("服务端socket 启动完成....");
// wait 主线程 后续的操作交给子线程处理
synchronized (Thread.currentThread()){
Thread.currentThread().wait();
}

}
}

package com.hrd.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

/**
* @author hurd@omeng.cc
* @version v0.1
* @date 2016/8/16
* @desc TODO
* @see
*/
public class ClientSocketMain {

public static void main(String[] args) throws IOException, InterruptedException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);

socketChannel.connect(new InetSocketAddress(8888));
Selector selector =  Selector.open();

SelectThread clientSelectThread = new SelectThread("client side:",selector);

socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);

clientSelectThread.start();

System.out.println("客户端启动完成....");
synchronized (Thread.currentThread()){
Thread.currentThread().wait();
}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: