NIO初探
来源:互联网 发布:java开发界面 编辑:程序博客网 时间:2024/06/05 14:40
NIO和旧IO的区别
NIO的涉及到的类
例子
一点学习NIO的心得,抛砖引玉,若有错误请高手指正。
NIO和旧IO的区别
NIO是传输是基于字节块的,而原来的IO是基于字节流的。NIO的优势不在于传输速度上,而是在其处理方式上。NIO使用selector来轮询可以使用的channel。selector的时下由底层jvm提供支持的。在连接(channel)很多个情况下,selector可以用来关心IO可用性,而线程高效的处理业务逻辑。
NIO相关类
- Channel:对底层I/O接口的一个抽象,可以打开底层I/O,比如socket,文件,磁盘等等。可以在在多个线程中共享
- Selector: 对可以选择的channel的一个多路选择器,可以从多个channel中选择出可以使用channel,所以selector和channel是一对多。
- Buffer:缓存块。其实普通IO我们也有Buffer封装类来加速IO处理。NIO定义了普通类型的buffer,比如ByteBuffer,IntBuffer,Longbuffer等。
例子
- 参考java网络编程中的Chargen协议,以socket为例,演示NIO的用法。CharGen主要是实现对访问的客户端返回顺序的字符串序列。
- 客户端socket相对简单些,步骤如下:
- 创建读取Channel 和ByteBuffer
- 创建写入Channel ,将读取的内容写入
package nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.Channels;import java.nio.channels.SocketChannel;import java.nio.channels.WritableByteChannel;public class CharGenClient { public static void main(String[] args) { // TODO Auto-generated method stub SocketChannel channel = null; WritableByteChannel writeChannel = null; try { //使用工厂方法声明一个Channel,指定网络链接 channel = SocketChannel.open(new InetSocketAddress("127.0.0.1",5536)); //将Channel绑定到指定端口(客户客户端的socket,让系统默认绑定一个本地端口) //channel.bind(); //分配一个缓冲区,以便接收服务端送来的数据块 ByteBuffer buffer = ByteBuffer.allocate(80); //创建一个写channel,将接收到到数据写到console writeChannel = Channels.newChannel(System.out); //轮询读取服务其的数据 while(channel.read(buffer)!=-1) { //限定Buffer的实际数据大小 buffer.flip(); //写入到输出channel writeChannel.write(buffer); //清空buffer,以便下次读取 buffer.clear(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if(channel != null) { try { //关闭channel writeChannel.close(); channel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }}
接着实现服务端。步骤如下:
- 定义服务端的Channel,并绑定到指定端口。并声明该channel为非阻塞的。
- 定义selector,将服务端的channel注册到selector,并指定关注事件类型为selectionkey.OP_ACCEPT。
- 简单的定义的轮询selector.select(); 这个事件会阻塞,直到有相关可以处理的SelectionKey.channel唤醒。
- 遍历selector.selectedKey(),根据Key的事件进行相关处理
- 如果是接收事件,则通过selectionKey获取对应的ServerSocketChannel。利用这个channel生成SocketChannel。并注册到刚刚的Selector 中,并关注写事件
- 如果是写事件,则分配ByteBuffer供后续Channel读取。
package nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Set;public class CharGenServer { /** * 服务端CharGen,接收客户端的访问,顺序输出字符串,直到客户端终止链接。使用NIO实现。</br> * 1、初始化服务端的Channel,以便监听来的请求</br> * 2、根据来的请求生成客户端Channel,返回字符串 * </br> * 使用到的类包括:Channel、Buffer、Selector、SelectorKey等 */ public static void main(String[] args) { // TODO Auto-generated method stub //初始化需要输出的内容,在内存中缓存 byte[] rotation = new byte[95*2]; for(byte i= ' ';i<= '~';i++) { rotation[i-' '] = i; rotation[i+95-' '] = i; } ServerSocketChannel server = null; SocketChannel client = null; Selector selector =null; try { //获取服务端socket的channel server = ServerSocketChannel.open(); //channel和指定的端口绑定,对外提供服务 server.bind(new InetSocketAddress(5536)); //设置服务端channel为非阻塞的,默认是阻塞的。 server.configureBlocking(false); //工厂方法调用selector selector = Selector.open(); //将服务端channel注册到selector,并指定关注类型为accept server.register(selector, SelectionKey.OP_ACCEPT); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } //select开始轮询 while(true) { try { //这是个阻塞方法,会等待该select对应的keys中至少一个Channel可以进行I/O操作。 selector.select(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); break; } //获取可以操作的keys,只允许从keyset中删除,不能直接添加。非线程安全的。 Set<SelectionKey> readyKeys = selector.selectedKeys(); //遍历seletionkey Iterator<SelectionKey> iterator = readyKeys.iterator(); while(iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove();//从Set删除待处理的key try { //判断key所属channel属于那类型的‘事件’ if(key.isAcceptable()) { //获取key对应的channel ServerSocketChannel s = (ServerSocketChannel)key.channel(); //因为服务端的channel是非阻塞的,所以稳妥点的化,需要判断返回的socketchannel是否为null。 client = s.accept(); System.out.println("Accepted connection from " + client); client.configureBlocking(false); //针对客户端的channel注册selector,以及关注的事件,以便提高处理效率,在链接空闲时,不占用系统资源 SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE); //分配缓存,这个是NIO处理的基本单元。 ByteBuffer buffer = ByteBuffer.allocate(74); buffer.put(rotation,0,72); buffer.put((byte)'\r'); buffer.put((byte)'\n'); buffer.flip(); //将分配的缓存对象作为selectionKey的附件,以便后续的channel可以使用 key2.attach(buffer); }else if (key.isWritable()) { client = (SocketChannel)key.channel(); //从附件中获取待处理的缓存 ByteBuffer buffer = (ByteBuffer)key.attachment(); if(!buffer.hasRemaining()) { buffer.rewind();//重置buffer的position到0 byte first = buffer.get();//获取第一个字符 buffer.rewind();//重置buffer的position到0 int position = first - ' ' + 1; buffer.put(rotation, position, 72); buffer.put((byte)'\r'); buffer.put((byte)'\n'); buffer.flip();//设置缓存中有效值的截止位置 } client.write(buffer);//将数据写入channel } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); key.cancel(); try { key.channel().close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } }/*finally {//不能放在finally中close channel,因为服务端的channel还不能关闭 key.channel().close(); }*/ } } }}
- NIO和旧IO的区别
- NIO相关类
- 例子
阅读全文
0 0
- NIO初探
- NIO初探
- java.nio包初探
- NIO机制初探
- 初探Java NIO
- Java NIO初探
- java nio初探
- Java NIO初探(一)
- Nio初探与netty实战
- Java NIO和Netty框架(一)初探NIO
- java-非阻塞异步通信-NIO初探
- Java Nio初探及普通io性能比较
- nio
- NIO
- NIO
- nio
- NIO
- NIO
- Android Toolbar使用
- 2013腾讯编程马拉松初赛第五场(3月25日)
- IO-1、输入输出设备
- scala变量访问范围
- 从0开始架构一个IOS程序——03 — -分包用添加pch全局引用文件
- NIO初探
- 设置内核线程的调度策略
- 修改mysql数据库字符集为UTF8的
- java 解决默认方法冲突
- Maven常用参数及其说明
- effective C++解读
- CodeForces
- bugku 考细心
- ios使用AVCaptureVideoDataOutput实现连续拍照消除快门声音