标签:大小 文件流 特定 address figure 处理 聊天 nts etl
NIO : new IO
有的文章说,NIO用到的是块,也就是每次读入较多的数据缓存,因此使用效率比IO要高些。
IO:面向流,阻塞IO
NIO:面向缓冲,非阻塞IO,有selector的支持。
阻塞IO 读写的好处,每次返回都必然是读写完成了,适用于一个线程处理一个连接,且连接处理发送接收数据量较大的情况。
非阻塞IO 每次读写返回未必是你想要的数据都读写完成了,即不会等待IO真正完成具体操作,因此在解析数据稍微复杂些。但是NIO由于是非阻塞IO,可以在一个线程中处理多个连接,特别适用于同时读写处理多个管道,且每个管道连接的收发数据量不大的情况,比如互联网中的聊天服务器。
Channel就如同IO流里面的Stream的概念。从Channel中读入数据到Buffer,或者从Buffer写入数据到Channel中。
Selector支持可以同时对多个Channel进行管理,任何一个Channel发生读写,Selector都能够知晓,从而做出对应处理。
Channel :
Buffer :缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
Buffer有两个模式:读模式 和 写模式。有三个属性,capacity、position、limit。理解了position和limit属性,你就能明白buffer了。
limit
在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。
当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)。
分配Buffer的capacity:CharBuffer buf = CharBuffer.allocate(1024);
compact()
将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
mark()与reset()方法
mark标记position的位置,这样即使后续在使用get之后,再使用reset方法,则position又回回到mark时候的位置。
private static Logger logger1 = Logger.getLogger(useNIO.class);
public static void testByteBuffer()
{
RandomAccessFile f;
try {
//创建文件流
f = new RandomAccessFile(".\\log\\nio.txt","rw");
//从文件流中获取channel
FileChannel channel = f.getChannel();
//分配1024个字节
ByteBuffer buf = ByteBuffer.allocate(1024);
int bytes = channel.read(buf);
while(bytes !=-1)
{
//切换buffer状态,从写入状态变为读取
buf.flip();
logger1.info("position:"+buf.position()+" limit:"+buf.limit());
//标记当前position的位置,用于之后的reset
buf.mark();
while(buf.hasRemaining())
{
logger1.info((char)buf.get());
logger1.info("position:"+buf.position()+" limit:"+buf.limit());
}
//position又回到mark时候的位置。
buf.reset();
logger1.info("after reset position:"+buf.position()+" limit:"+buf.limit());
//将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
buf.compact();
logger1.info("after compact position:"+buf.position()+" limit:"+buf.limit());
//position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。
buf.clear();
logger1.info("after clear position:"+buf.position()+" limit:"+buf.limit());
bytes = channel.read(buf);
}
f.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
Selector,用于对多个Channel进行管理使用,大大提高效率的示例:
private static ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
public static void testSelector()
{
int port = 33333;
Selector selector;
try
{
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.bind(new InetSocketAddress("127.0.0.1", port));
selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
logger1.info("[系统消息提示]监听端口" + port);
while(true)
{
try
{
selector.select(1000); //可以设置超时时间,防止进程阻塞
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> selectionKeyIte = selectionKeys.iterator();
while(selectionKeyIte.hasNext()){
SelectionKey selectionKey = selectionKeyIte.next();
selectionKeyIte.remove();
DoSomeThing(selectionKey,selector);
}
}
catch(Exception e)
{
}
}
}
catch
(Exception e)
{
}
}
public static void DoSomeThing(SelectionKey selectionKey,Selector selector)throws IOException
{
ServerSocketChannel server = null;
SocketChannel channel = null;
String receiveText;
int count;
if(selectionKey.isAcceptable()){
try {
server = (ServerSocketChannel) selectionKey.channel();
channel = server.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
}
catch (IOException e)
{
e.printStackTrace();
}
}
else if(selectionKey.isReadable())
{ //获取通道对象,方便后面将通道内的数据读入缓冲区
channel = (SocketChannel) selectionKey.channel();
receiveBuffer.clear();
count = channel.read(receiveBuffer); //如果读出来的客户端数据不为空
if(count>0)
{
receiveText = new String(receiveBuffer.array(),0,count);
logger1.info("[系统消息提示]服务器发现["+receiveText+"]new connect"); }
else
{
logger1.info("[系统消息提示]someone disconnect");
selectionKey.cancel();
}
}
}
标签:大小 文件流 特定 address figure 处理 聊天 nts etl
原文地址:http://blog.51cto.com/ggwhsd/2341370