非阻塞I/O可以减少服务器无用的等待,从而高效的处理其他工作。能够让一个线程负责多个连接,而不是为每一个Socket都分配一个连接,在该线程中,选取负责多个连接中的一个已经准备好接收数据的连接,从而尽快的用数据进行填充,进而转下下一个准备好的连接。
传统意义上的连接,会每次都会产生大量的线程,线程切换会耗费很大的时间。
当然非阻塞I/O主要是未服务器端设计的,不过这里是主要模拟一下,论述客户端利用通道和缓冲区的时候的流程。
在这里实例一个客户端的基于通道和缓冲区的连接。package com.nio.client;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
public class ChargenClient {
private static final int DEFAULT_PORT=19;
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
SocketAddress address =new InetSocketAddress("localhost",2222);
//利用给定的主机和端口创建一个通道,此时会自动连接,默认打开的通道是阻塞状态道
//下一行代码在建立连接之前不会被执行,失败会抛出一个IOException
SocketChannel client=SocketChannel.open(address);
//设置该通道未非阻塞状态
client.configureBlocking(false);
//将读取的数据直接写入到通道中,不需要寻找该Socket的输入流
//但是写入与写出的需要ByteBuffer 对象
ByteBuffer buffer=ByteBuffer.allocate(80);
//这里先构造一个向System.out写入字节的通道
//但是它不对所得的信道进行缓冲,只是将其 I/O 操作重定向到给定的流
WritableByteChannel out=Channels.newChannel(System.out);
//将此buffer对象传递给通道client的read方法,通道会将从
//socket读取的数据自动的填充到该缓冲区buffer
//当缓冲区buffer有数据后,就会被复制到System.out
while(client.read(buffer)!=-1)
{
//目的是从缓冲区的开头读取
buffer.flip();
out.write(buffer);
//这里只是将缓冲区重置到初始状态,但是其缓冲区的数据依旧还在,
//只不过会被新的数据马上覆盖
buffer.clear();
}
//非阻塞下读取数据方式,
//由于在非阻塞下,read会至少读取一个字节,当读取不到数据的时候返回0
while(true)
{
int n=client.read(buffer);
if(n>0)
{
buffer.flip();
out.write(buffer);
buffer.clear();
}
else if( n==-1)
{
break;
}
}
}catch(IOException e)
{
System.out.println(e);
}
}
}