非阻塞I/O可以减少服务器无用的等待,从而高效的处理其他工作。能够让一个线程负责多个连接,而不是为每一个Socket都分配一个连接,在该线程中,选取负责多个连接中的一个已经准备好接收数据的连接,从而尽快的用数据进行填充,进而转下下一个准备好的连接。

 传统意义上的连接,会每次都会产生大量的线程,线程切换会耗费很大的时间。

 当然非阻塞I/O主要是未服务器端设计的,不过这里是主要模拟一下,论述客户端利用通道和缓冲区的时候的流程。

 在这里实例一个客户端的基于通道和缓冲区的连接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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);
         }
     }
}