Java NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源的。
Java NIO非堵塞技术实际是采取Reactor模式,或者说是Observer模式为我们监察I/O端口,如果有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。
Java NIO出现不只是一个技术性能的提高,你会发现网络上到处在介绍它,因为它具有里程碑意义,从JDK1.4开始,Java开始提高性能相关的功能,从而使得Java在底层或者并行分布式计算等操作上已经可以和C或Perl等语言并驾齐驱。
简单说:使用java nio开发网络通讯 是比较快速和方面的。因为他可以不用阻塞的方式侦听客户端的连接 ,在java nio中可以使用基于事件的机制进行非阻塞通讯,当有新的事
件进行注册时 我们只需要通过事件侦听机制 获取新的事件
简单的说就是 java nio中里面有一个selector 异步 I/O 中的核心对象名为 Selector。Selector 就是您注册对各种 I/O 事件的兴趣的地方。
下面上代码,注释说明
class="java">
package nio.socket;
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;
import org.junit.Test;
public class Server {
@Test
public void server() throws IOException {
//selector就是您注册对各种io事件的兴趣的地方 而且当那些事件发生时 就是这个对象告诉您所发生的事情
Selector selector = Selector.open();
//开启一个ServerSocketChannel通道
ServerSocketChannel ssc = ServerSocketChannel.open();
//绑定地址和端口
ssc.bind(new InetSocketAddress("localhost", 8080));
// 设置为非阻塞式的IO
ssc.configureBlocking(false);
//注册感兴趣的
ssc.register(selector, SelectionKey.OP_ACCEPT);
//设置一个缓冲
ByteBuffer buffer = ByteBuffer.allocate(1024);
//接收客户端过来的通道
SocketChannel sc = null;
while (true) {
selector.select(); //查询事件,监听一旦有我们注册的感兴趣的事件发生的时候便会激活
Set<SelectionKey> selectedKeys = selector.selectedKeys(); //获取到触发的事件集合
SelectionKey key = null;
Iterator<SelectionKey> iterator = selectedKeys.iterator();
for (;iterator.hasNext();) {//循环
key = iterator.next();
if(key.isAcceptable()){ //表示触发的事件是新连接
ServerSocketChannel newssc = (ServerSocketChannel) key.channel();
sc = newssc.accept(); //获取到客户端过来的通道
sc.configureBlocking(false); //设置为非阻塞式IO
sc.register(selector, SelectionKey.OP_READ);//注册读取事件
iterator.remove(); //事件集合中删除
System.out.println("有新的连接");
}else if(key.isReadable()){ //表示读取事件 在连接时候注册了读取事件 在这里处理
sc = (SocketChannel) key.channel(); //得到客户端的通道
while(true){
buffer.clear(); //如果信息量超过预设的缓存就会便会批量读取 重复使用 这里必须清理一下
int read = sc.read(buffer);
if(read == -1 || read == 0)break; //如果读取完了 则退出循环
if(read > 0){
byte[] array = buffer.array();
System.out.println("接受到的数据"+new String(array));
}
}
buffer.clear();
buffer.put("这是我的测试".getBytes());
buffer.flip();//flip方法将Buffer从写模式切换到读模式
sc.write(buffer);
sc.close();//使用完毕关闭客户端的通道
System.out.println("操作结束==============");
iterator.remove();
}
}
}
}
}