非阻塞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