Java NIO基本使用
2016-02-17 22:58
423 查看
NIO是Java提供的非阻塞I/OAPI.
非阻塞的意义在于可以使用一个线程对大量的数据连接进行处理,非常适用于"短数据长连接"的应用场景,例如即时通讯软件.
在一个阻塞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
然后是Client
此外有一个代码写得更好的例子,非常值得参考.http://rox-xmlrpc.sourceforge.net/niotut/index.html
这个例子里面的客户端将消息发送给服务器,服务器收到后立即写回给客户端.例子中代码虽然也没有做有意义的处理,但是其结构比较合理,值得以此为基础进行现实应用的扩展开发.
非阻塞的意义在于可以使用一个线程对大量的数据连接进行处理,非常适用于"短数据长连接"的应用场景,例如即时通讯软件.
在一个阻塞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 | * |
15 | * |
16 | * |
17 | */ |
18 | public class Server |
19 | private Selector |
20 | private ByteBuffer 8 ); //调整缓存的大小可以看到打印输出的变化 |
21 | private Map<SocketChannel, byte []> new ConcurrentHashMap<>(); |
22 |
23 | public void start() throws IOException |
24 | ServerSocketChannel |
25 | ssc.configureBlocking( false ); |
26 | ssc.bind( new InetSocketAddress( "localhost" , 8001 )); |
27 | selector |
28 | ssc.register(selector,SelectionKey.OP_ACCEPT); |
29 | while (!Thread.currentThread().isInterrupted()) |
30 | selector.select(); |
31 | Set<SelectionKey> |
32 | Iterator<SelectionKey> |
33 | while (keyIterator.hasNext()) |
34 | SelectionKey |
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 throws IOException |
49 | SocketChannel |
50 |
51 | // |
52 | this .readBuffer.clear(); |
53 |
54 | // |
55 | int numRead; |
56 | try { |
57 | numRead this .readBuffer); |
58 | } catch (IOException |
59 | // |
60 | // |
61 | key.cancel(); |
62 | socketChannel.close(); |
63 | clientMessage.remove(socketChannel); |
64 | return ; |
65 | } |
66 |
67 | byte [] |
68 | if (bytes null ) |
69 | bytes new byte [ 0 ]; |
70 | } |
71 | if (numRead 0 ) |
72 | byte [] new byte [bytes.length |
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 new String(bytes); |
79 | System.out.println(message); |
80 | } |
81 | } |
82 |
83 | private void accept(SelectionKey throws IOException |
84 | ServerSocketChannel |
85 | SocketChannel |
86 | clientChannel.configureBlocking( false ); |
87 | clientChannel.register(selector,SelectionKey.OP_READ); |
88 | System.out.println( "a ); |
89 | } |
90 |
91 |
92 | public static void main(String[] throws IOException |
93 | System.out.println( "server ); |
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 | * |
15 | * |
16 | * |
17 | */ |
18 | public class Client |
19 |
20 | public void start() throws IOException |
21 | SocketChannel |
22 | sc.configureBlocking( false ); |
23 | sc.connect( new InetSocketAddress( "localhost" , 8001 )); |
24 | Selector |
25 | sc.register(selector,SelectionKey.OP_CONNECT); |
26 | Scanner new Scanner(System.in); |
27 | while ( true ) |
28 | selector.select(); |
29 | Set<SelectionKey> |
30 | System.out.println( "keys=" + |
31 | Iterator<SelectionKey> |
32 | while (keyIterator.hasNext()) |
33 | SelectionKey |
34 | keyIterator.remove(); |
35 | if (key.isConnectable()) |
36 | sc.finishConnect(); |
37 | sc.register(selector,SelectionKey.OP_WRITE); |
38 | System.out.println( "server ); |
39 | break ; |
40 | } else if (key.isWritable()) |
41 |
42 | System.out.println( "please ); |
43 | String |
44 | ByteBuffer |
45 | sc.write(writeBuffer); |
46 | } |
47 | } |
48 | } |
49 | } |
50 |
51 | public static void main(String[] throws IOException |
52 | new Client().start(); |
53 | } |
54 | } |
这个例子里面的客户端将消息发送给服务器,服务器收到后立即写回给客户端.例子中代码虽然也没有做有意义的处理,但是其结构比较合理,值得以此为基础进行现实应用的扩展开发.
相关文章推荐
- [017]Java设计模式3——策略模式
- javaWeb安全篇(1)——防盗链技术的实现
- Java开发中的23种设计模式详解
- java byte to hex
- Java 中的悲观锁和乐观锁的实现
- 用java多线程断点续传实践
- Java中try-catch结构
- SpringMVC的实现过程
- JAVA中的反射机制
- Java 编码问题总结
- Spring中Bean的实例化
- Java反射机制
- CenOS6.5安装JDK1.7
- JAVA中复制数组、对象数组拷贝
- [转] 使用Spring MVC构建REST风格WEB应用
- 工厂模式 Java设计模式笔记
- Spring学习之基本概念
- 我的第一篇关于Java基础博客
- Andriod学习笔记4:mac下搭建 Eclipse+CDT 集成开发环境
- Java编程入门(词汇表)