非阻塞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);
}
}
} |
本文转自 zhao_xiao_long 51CTO博客,原文链接:http://blog.51cto.com/computerdragon/1197500