Java NIO基本使用
来源:互联网 发布:windows管理模板 编辑:程序博客网 时间:2024/06/05 09:43
NIO是Java提供的非阻塞I/O API.
非阻塞的意义在于可以使用一个线程对大量的数据连接进行处理,非常适用于"短数据长连接"的应用场景,例如即时通讯软件.
在一个阻塞C/S系统中,服务器要为每一个客户连接开启一个线程阻塞等待客户端发送的消息.若使用非阻塞技术,服务器可以使用一个线程对连接进行轮 询,无须阻塞等待.这大大减少了内存资源的浪费,也避免了服务器在客户线程中不断切换带来的CPU消耗,服务器对CPU的有效使用率大大提高.
其核心概念包括Channel,Selector,SelectionKey,Buffer.
Channel是I/O通道,可以向其注册Selector,应用成功可以通过select操作获取当前通道已经准备好的可以无阻塞执行的操作.这由SelectionKey表示.
SelectionKey的常量字段SelectionKey.OP_***分别对应Channel的几种操作例如connect(),accept(),read(),write().
select操作后得到SelectionKey.OP_WRITE或者READ即可在Channel上面无阻塞调用read和write方 法,Channel的读写操作均需要通过Buffer进行.即读是讲数据从通道中读入Buffer然后做进一步处理.写需要先将数据写入Buffer然后 通道接收Buffer.
下面是一个使用NIO的基本C/S示例.该示例只为显示如何使用基本的API而存在,其代码的健壮性,合理性都不具参考价值.
这个示例,实现一个简单的C/S,客户端想服务器端发送消息,服务器将收到的消息打印到控制台.现实的应用中需要定义发送数据使用的协议,以帮助服 务器解析消息.本示例只是无差别的使用默认编码将收到的字节转换字符并打印.通过改变初始分配的ByteBuffer的容量,可以看到打印消息的变化.容 量越小,对一条消息的处理次数就越多,容量大就可以在更少的循环次数内读完整个消息.所以真是的应用场景,要考虑适当的缓存大小以提高效率.
首先是Server
01
package
hadix.demo.nio;
02
03
import
java.io.IOException;
04
import
java.net.InetSocketAddress;
05
import
java.nio.ByteBuffer;
06
import
java.nio.channels.SelectionKey;
07
import
java.nio.channels.Selector;
08
import
java.nio.channels.ServerSocketChannel;
09
import
java.nio.channels.SocketChannel;
10
import
java.util.*;
11
import
java.util.concurrent.ConcurrentHashMap;
12
13
/**
14
* User: hAdIx
15
* Date: 11-11-2
16
* Time: 上午11:26
17
*/
18
public
class
Server {
19
private
Selector selector;
20
private
ByteBuffer readBuffer = ByteBuffer.allocate(
8
);
//调整缓存的大小可以看到打印输出的变化
21
private
Map<SocketChannel,
byte
[]> clientMessage =
new
ConcurrentHashMap<>();
22
23
public
void
start()
throws
IOException {
24
ServerSocketChannel ssc = ServerSocketChannel.open();
25
ssc.configureBlocking(
false
);
26
ssc.bind(
new
InetSocketAddress(
"localhost"
,
8001
));
27
selector = Selector.open();
28
ssc.register(selector, SelectionKey.OP_ACCEPT);
29
while
(!Thread.currentThread().isInterrupted()) {
30
selector.select();
31
Set<SelectionKey> keys = selector.selectedKeys();
32
Iterator<SelectionKey> keyIterator = keys.iterator();
33
while
(keyIterator.hasNext()) {
34
SelectionKey key = keyIterator.next();
35
if
(!key.isValid()) {
36
continue
;
37
}
38
if
(key.isAcceptable()) {
39
accept(key);
40
}
else
if
(key.isReadable()) {
41
read(key);
42
}
43
keyIterator.remove();
44
}
45
}
46
}
47
48
private
void
read(SelectionKey key)
throws
IOException {
49
SocketChannel socketChannel = (SocketChannel) key.channel();
50
51
// Clear out our read buffer so it's ready for new data
52
this
.readBuffer.clear();
53
54
// Attempt to read off the channel
55
int
numRead;
56
try
{
57
numRead = socketChannel.read(
this
.readBuffer);
58
}
catch
(IOException e) {
59
// The remote forcibly closed the connection, cancel
60
// the selection key and close the channel.
61
key.cancel();
62
socketChannel.close();
63
clientMessage.remove(socketChannel);
64
return
;
65
}
66
67
byte
[] bytes = clientMessage.get(socketChannel);
68
if
(bytes ==
null
) {
69
bytes =
new
byte
[
0
];
70
}
71
if
(numRead >
0
) {
72
byte
[] newBytes =
new
byte
[bytes.length + numRead];
73
System.arraycopy(bytes,
0
, newBytes,
0
, bytes.length);
74
System.arraycopy(readBuffer.array(),
0
, newBytes, bytes.length, numRead);
75
clientMessage.put(socketChannel, newBytes);
76
System.out.println(
new
String(newBytes));
77
}
else
{
78
String message =
new
String(bytes);
79
System.out.println(message);
80
}
81
}
82
83
private
void
accept(SelectionKey key)
throws
IOException {
84
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
85
SocketChannel clientChannel = ssc.accept();
86
clientChannel.configureBlocking(
false
);
87
clientChannel.register(selector, SelectionKey.OP_READ);
88
System.out.println(
"a new client connected"
);
89
}
90
91
92
public
static
void
main(String[] args)
throws
IOException {
93
System.out.println(
"server started..."
);
94
new
Server().start();
95
}
96
}
01
package
hadix.demo.nio;
02
03
import
java.io.IOException;
04
import
java.net.InetSocketAddress;
05
import
java.nio.ByteBuffer;
06
import
java.nio.channels.SelectionKey;
07
import
java.nio.channels.Selector;
08
import
java.nio.channels.SocketChannel;
09
import
java.util.Iterator;
10
import
java.util.Scanner;
11
import
java.util.Set;
12
13
/**
14
* User: hAdIx
15
* Date: 11-11-2
16
* Time: 上午11:26
17
*/
18
public
class
Client {
19
20
public
void
start()
throws
IOException {
21
SocketChannel sc = SocketChannel.open();
22
sc.configureBlocking(
false
);
23
sc.connect(
new
InetSocketAddress(
"localhost"
,
8001
));
24
Selector selector = Selector.open();
25
sc.register(selector, SelectionKey.OP_CONNECT);
26
Scanner scanner =
new
Scanner(System.in);
27
while
(
true
) {
28
selector.select();
29
Set<SelectionKey> keys = selector.selectedKeys();
30
System.out.println(
"keys="
+ keys.size());
31
Iterator<SelectionKey> keyIterator = keys.iterator();
32
while
(keyIterator.hasNext()) {
33
SelectionKey key = keyIterator.next();
34
keyIterator.remove();
35
if
(key.isConnectable()) {
36
sc.finishConnect();
37
sc.register(selector, SelectionKey.OP_WRITE);
38
System.out.println(
"server connected..."
);
39
break
;
40
}
else
if
(key.isWritable()) {
41
42
System.out.println(
"please input message"
);
43
String message = scanner.nextLine();
44
ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes());
45
sc.write(writeBuffer);
46
}
47
}
48
}
49
}
50
51
public
static
void
main(String[] args)
throws
IOException {
52
new
Client().start();
53
}
54
}
此外有一个代码写得更好的例子,非常值得参考.http://rox-xmlrpc.sourceforge.net/niotut/index.html
这个例子里面的客户端将消息发送给服务器,服务器收到后立即写回给客户端.例子中代码虽然也没有做有意义的处理,但是其结构比较合理,值得以此为基础进行现实应用的扩展开发.
- Java NIO基本使用
- Java NIO基本使用
- java.nio --Path--Files--基本使用
- Nio基本使用
- nio基本使用
- nio基本使用一
- java NIO基本操作
- NIO学习二、NIO的基本使用
- java NIO使用示例
- java NIO 使用实例
- Java中的NIO使用
- java nio 使用例子
- java nio使用
- java为什么使用nio
- Java NIO的使用
- Java NIO使用分析
- java nio的使用
- Java NIO使用
- iOS7之后如何正确隐藏状态栏
- vi VS emacs
- 三星450r5j设置U盘启动
- Heat/ApplicationDeployment
- android:id="@id"与android:id="@+id/"的区别
- Java NIO基本使用
- 蓝桥杯—翻硬币
- 也谈JVM垃圾回收
- 用Qt实现一个桌面弹幕程序(四)--实现一个弹幕③
- 【图像处理】相机成像原理
- Android 删除手机相册中的图片
- Demo2:简单求职表格
- [017]Java设计模式3——策略模式
- Android 个人开发者接入支付功能