java NIO笔记

非阻塞通信
阻塞通信意味着通信方法在尝试访问套接字或者读写数据时阻塞了对套接字的访问。非阻塞通信允许网络通信在应用程序和没有阻塞的进程中使用套接字。JDK1.4之前,绕过阻塞限制地方法是无限制的使用线程(老版Tomcat就是这样做的,为每个用户单独建立一个线程),但这常常会造成大量的线程开销,影响系统性能。
对于同步通信,不必在读取数据之前处理其他数据,阻塞通信更好些,而非阻塞通信提供了处理任何已经读取的数据的机会,适合于处理如聊天客户机等要求避免冻结套接字的异步通信。
Java NIO的非阻塞I/O机制围绕选择器(Selector)和通道构建,selector类似于一个观察者,只要把需要探知的socketChannel告诉selector,接着就可做别的事情,(selector内部实际是做对所注册的channel的轮询访问)当有事件发生时,selector返回一组SelectionKey,通过读取这些key,就可以获得刚刚注册过的socketChannel,然后从这个Channel中读取数据,再处理这些数据。通道表示连接到一个实体(如:硬件设备、文件、网络套接字等)的开放连接。可以异步的关闭和中断NIO通道。如果一个线程在某条通道的I/O操作上阻塞,另一个线程可以关闭这条通道。非阻塞通信使用通道(Channel)进行客户机和服务器通信。
网络通信中使用java.nio.channels.Socket接口和java.nio.channels.ServerSocketChannel接口代替Socket和ServerSocket。
编程中用到的相关类
1. InetSocketAddress(指定连接到哪里,通过指定服务器地址和端口号来创建该类的对象)
InetSocketAddress isa=new InetSocketAddress(“Ip地址或网址”,端口号);
2. SocketChannel(执行实际的读写操作)
客户端建立连接步骤
(1) 调用open(InetSocketAddress isa)方法创建通道对象,新创建的通道已打开,但尚未连接。注意,不能使用new来创建SocketChannel对象(这里用sc表示)。
(2) 调用sc.connect()方法发起到远程套接字的连接,该方法返回时套接字不一定是连接的,必须有第(3)步。可调用isConnectionPending方法确定是否正在进行连接操作。
(3) 通过sc.finishConenct()方法完成连接,可用isConnected()方法判断是否已建立连接。
(4) 通过int read(ByteBuffer[] dst,int offset, int length)方法将字节序列从通道中读入给定的缓冲区.
(5) 通过int write(ByteBuffer[] srcs,int offset, int length)将字节序列从缓冲区写入此通道
(6) 调用sc.close()方法关闭连接
注:sc.configureBlocking(Boolean bool)方法用于调整通道的阻塞模式,java NIO使用通道而非流,通道可同时用于阻塞和非阻塞模式,创建时默认为阻塞版本。bool值设为false时为非阻塞模式。
sc.socket()方法可获取与此通道相关联的套接字。
3. ServerSocketChannel(服务器套接字通道不是侦听网络套接字的完整抽象。必须通过调用socket方法获得与之关联的ServerSocket对象来完成对套接字选项的绑定和操作)
服务器端编程步骤
(1) 调用open()方法创建服务器套接字通道对象(这里用ssc),新创建的通道已打开,但尚未绑定此时调用accept方法会抛出NotYetBoundException。
(2) 调用ssc.socket()方法获得与之关联的ServerSocket对象(这里用ss表示)。
(3) 调用ss.bind(new InetSocketAddress(port))进行绑定。
(4) 创建选择器Selector selector=Selector.open();注意,不能用new创建。
(5) 调用ssc.register(selector,SelectionKey.OP_ACCEPT);方法将套接字通道和选择器注册。此处注册为OP_ACCEPT类型。当客户端出现尝试连接操作时,服务器程序便获得一个由选择器创建的关键字。当一个关键字被处理是,应调用remove()方法将其从这组关键字中移除,以免重复迭代。
(6) SocketChannel sc=ssc.accept()使用服务器套接字通道对象的accept()方法接受到来的连接并转个一个套接字通道,通信就可以通过这个新的通道对象的read()和write()方法进行读写操作了。
注:细节见源代码
4. SelectionKey类
当一些有意义的时间发生在通道上时,选择器便会通知应用程序处理请求。选择器会创建一个关键字,这个关键字是SelectionKey类的一个实例。每个关键字都保存这应用程序的表示及其请求类型。请求类型有四种:
(1) 尝试连接(客户端) 关键字:SelectionKey.OP_ACCEPT
(2) 尝试连接(服务器端) 关键字:SelectionKey.OP_CONNECT
(3) 读取操作 关键字:SelectionKey.OP_READ
(4) 写入操作 关键字:SelectionKey..OP_WRITE
5.Selector是SelectableChannel(所用通道的顶级接口)的多路复用
可调用Selector对象的select()方法轮询查询选择器,以等待事件发生。
当客户端应用程序同时执行对服务器端的请求时,选择器将其集中起来创建关键字并发送至服务器端,开起来像阻塞体系(因为一定时间内只处理一个请求),但实际上,每个关键字仅代表从客户端发送至服务器的部分信息。选择器能分割那些被关键字标识的子请求里的数据,因此,当连续的数据发送至服务器端时,选择器会创建更多的根据时间共享策略来进行处理的关键字。
6.Buffer(缓冲区,一个用于特定基本数据类型的容器)
相关属性:
(1)容量,缓冲区包含元素的数量,用对象的int capacity()方法返回。
(2)限制,第一个不应该读取或写入的元素的索引,用对象的int limit()方法返回
(3)位置,下一个要读取或写入的元素的索引。相对读操作从当前位置开始,将位置增加所传输的元素个数,每次操作后位置变动;绝对操作采用显式元素索引,操作后不影响位置。
Buffer对象常用方法:
(1)Object array() 返回此缓冲区底层实现数组。
(2)Buffer clear() 清除缓冲区
(3)flip()反转此缓冲区
(4)boolean hasArray()判断此缓冲区是否有可访问的底层实现数组。
(5)hasRemaining()判断当前位置和限制之间是否有元素。
(6)boolean isReadOnly()判断是否为只读缓冲区
(7)put()向缓冲区中写数据
(8)get()从缓冲区读数据
(9)position(int pos)设置位置
Buffer的子类有ByteBuffer、CharBuffer等,可用Buffer类的静态方法allocate(int 大小)、allocateDirect(int 大小)(直接使用操作系统来分配Buffer,速度更快)、和wrap(与缓冲区相同类型的数组)来创建缓冲区对象。
附 注
异步通信”是一种很常用的通信方式。异步通信在发送字符时,所发送的字符之间的时间间隔可以是任意的。当然,接收端必须时刻做好接收的准备。
“同步通信”的通信双方必须先建立同步,即双方的时钟要调整到同一个频率。收发双方不停地发送和接收连续的同步比特流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值