NIO Socket

NIO non-blocking ,Sun官方标榜的特征是:为原始的数据类型提供缓存服务

Channel 一个新的原始IO抽象

 

缓存区Buffer

一个存储原始数据类型的容器,它的底层就是一个数组,它用4个核心属性对数组进行了封装限制。

 

缓冲区的4个核心技术

capacity limit position mark

 

缓冲区可以用两个静态方法创建 wrap allocate

 

capacity代表了这个底层数组的长度大小,从1开始

 

limit 表示返回一个 index,从0开始,表示从这个index开始,后面的元素都是不可读不可写的。 即如果index=3,那么访问array[3]会返回异常。

 

position 表示返回下一个可读可写的index,也是从0开始。

 

mark标记,它记录当前position的位置,源码是 this.marl=position

 

获取缓冲区剩余空间的大小,remaining() ,源代码是 return limit - position ;

 

reset()方法前,标识mark必须不等于-1,它会让position = mark ;

 

直接缓存区

一般而言,在JVM会缓存硬盘的内容,然后再传递给Buffer ;而直接缓存区 就是省去JVM的中间缓存 ,直接把硬盘的内容读取到 Buffer 中。

 

isDirect()

 

还原缓存区的内容   一般这个方法用在往缓存区写入内容前使用

clear()  

{

position=0; limit=capacity ; mark =-1;

}

缩小缓存区,一般用在写完缓存区后,要读取之前调用

flip()

{

limit=position ; position=0 ; mark =-1;

}

判断缓存区是否有底层实现数组

hasArray()

判断是否还有剩余的元素读取

hasRemaining { position <limit}

 

一般用在重写写入缓存区

rewind()  

position=0 ; mark =-1;

}

 

arrayOffset  返回缓存区第一个元素在 底层数组的偏移量,即第一个缓存元素在数组的下标index。

 

List.toArray(T[])

 

ByteBuffer CharBuffer

 

slice方法,是创建新的缓存区,不过它还是共用底层数组,它的position是 原来的缓存区的limit 的下标

 

使用ByteBuffer CharBuffer处理中文输入

ByteBuffer默认使用的是utf8,CharBuffer使用的是utf-16BE

 

如果读取中文的时候,使用的编码格式是utf8,或者GBK,那么就需要经过特殊的转换。

  使用获取 字节数组 getBytes("utf-16BE")  ; 用byteBuffer.asCharBuffer() 将UTF-16BE的ByteBuffer对象转换成CharBuffer对象

  使用Charset.forName("UTF-8").decode(bytebuffer)

 

order() 定义CPU读取字符的顺序,默认是从高位读取,但是有的CPU可能会从地位读取。

 

通道Channel

  传输 数据 的 通路。

 

Channel接口  它的父接口是 Closeable接口,而Closeable接口 的父接口是 AutoCloseable接口

AutoCloseable接口的close方法,具有自动关闭资源的功能,强调在try块中使用。

而 Closeable接口重写的close方法,具有幂等性,用于关闭I/O流。

 

 

AsynchronousChannel子接口

具有异步I/O操作,它的方法是operation , 这个方法具有两个重载,能与异步的线程进行交流,返回值是 Future接口

 

NetworkChannel 接口,主要用于和Socket交互

AbstractInterruptibleChannel 接口,是提供一个可以被中断的通道实现类

 

FileChannel 类

该个通道永远是阻塞的。

它在内部一个当前文件的position,可以对其进行查询和修改,该个文件本身包含一个可读,可写的字节序列

 

不太常用的方法

truncate(long size )  通道的文件截取给定大小,如果文件的大小大于 size ,那么丢弃 多余的。

transferTo() transferFrom()

 

FileLock  lock(long position , long size , boolean shared )

共享锁,只能进行读操作;独占锁,自己能进行读写操作。

 

force(boolean meta) 强制所有对此通道的文件更新重新写入包含该文件的存储设备,如果传入值是true ,那么对文件内容和元数据进行更新。

 

MappedByteBuffer map(FileChannel.MapMode mode ,long position , long size )

将文件区域直接映射到内存。

 

open 打开一个文件

ioOpen

 

获取网络设备信息

 

NetworkInterface 类 表示一个有名称和分配给这个接口的IP列表的网络接口

 

getName

getDisplayName

getIndex

isUp  网卡是否开启

isLoopback  回调/回环接口 ,它是一个虚拟的,永远工作的虚拟接口

getMTU

 

获取子接口

getSubInterfaces

isVirtural

getParent

 

getHardwareAddress 硬件地址

getInetAddress 获取IP地址

 

InetAddress类的方法

getCanonicalHostName 

getHostName

getHostAddress

getAddress 

 

 

getLocalHost 返回主机的IP 如果有多个,返回第一个IP

getAllByName 通过名字放回主机IP

 

InetAddress  getByName(host )

 

InterfaceAddress 类 可以获取网络接口的IP,子网掩码,广播地址等信息,对于IP6还能得到网络前缀

 

 

判断设备是否为点对点设备,支持多播等方法

 

基于TCP的 Socket通信

 

ServerSocket类 

accept 方法具有阻塞性

 

三次握手的 时机 创建ServerSocket 对象,并且绑定指定的端口和IP地址

 

ServerSocket类的使用

设置超时时间 setSoTimeout(ms)客户端在超时时间之内没有 成果连接,那么会发生异常

 

构造函数的 参数 backlog , 接受客户端的连接的个数,默认是50,多余的请求会被忽略

bind(SocketAddress )  服务端绑定指定的socket地址

 

SocketAddress  和 InetAddress  是两个不同的类,前面的类是socket地址,包括了IP地址和端口号,而后面的地址仅有IP地址。

 

SocketAddress 的子类是 InetSocketAddress

 

获取服务端本地绑定的socket地址 getLocalSocketAddress   getLocalPort

 

获取主机名

getHostName 如果是IP地址创建的,那么它会通过DNS反向查找,返回主机的名字

getHostString  直接返回主机名或者IP地址

 

isUnresolved 如果域名无法解析,那么返回true,解析成功,返回false

 

Socket 的ReuseAddress选项

setReuseAddress() 端口是否允许复用

在TCP发起关闭请求后,一端进入TIME_WAIT 状态后,等待一段时间才关闭连接,在等待时间内,可以允许端口进行使用。

 

Socket 的ReceiveBuffer选项

 ServerSocket接受套接字的SO_RCVBUF选项设置新值, 即服务端的接收缓存区的大小

 

Socket类的使用

bind  绑定本地的套接字

connect(SocketAddress ) 连接远程服务端的套接字

 

getPort获取远程端口

getLocalPort获取本地接口

 

Socket TcpNoDelay选项

控制是否采用Nagle算法,会将数据压缩到一个大包后,再传输。

 

Socket SendBufferSize选项

设置发生缓存区的大小 SO_SNDBUF

 

 Socket Linger选项

控制socket关闭close行为,close后,但是底层套接字可能还没有关闭,因为留在缓存区的数据还没有发生完成。

 

Socket OOBinline

开启这个选项,套接字将接收所以TCP紧急数据,通过输入流接收。

关闭这个选项,紧急数据将会被丢弃

 

Socket KeepAlive选项

设置true时,如果某个端长时间内没有数据传输,那么就会发送一个ACK探测包,如果没有接收到ACK包,那么这个连接将会被关闭。

 

Socket TrafficClass选项

定性描述TCP连接的传输质量

 

 

 

UDP

客户端和服务端使用的是 DatagramSocket类 ,数据发送使用的是DatagramPacket类

 

UDP理论上的最大一个包只能传输 2的16次方 -1 =65535字节,但实际上 65535-20-8 =65507字节

 

组播 MulticastSocket 

 

选择器

 

Selector 多路复用选择器

SelectorKey  register方法后,返回的注册凭借

SelectableChannel  通道,使用regster方法,向选择器注册

 

一个通道可以向多个选择器注册,一个通道对一个选择器多次注册返回的凭借是 一样的。

 

一个多路选择器可以 处理1023个通道

 

SelectableChannel  是一个抽象类,它的平行类是FileChannel , 它有三个实现子类

分别是ServerSocketChannel SocketChannel DatagramChannel

这些子类都是通过静态的open方法创建实例对象

 

register(selector, int pos) 返回的是一个SelectorKey 代表该个通道已经向选择器注册了,返回凭证。  服务端的操作是接收,而客户端的可选操作,是可连接,可读,可写。

可以通过SelectorKey cancel方法显示地取消注册

 

新创建的ServerSocketChannel 都是非阻塞的,需要调用configureBlocking(true) 设置成阻塞的。

 

非阻塞模式下,accept方法如果没有客户端连接,返回null

如果accept方法,返回了一个 SocketChannel ,那么需要将它注册到 Selector上,实现多路复用。

 

注意:如果要注册到选择器,那么需要将通道设置成非阻塞模式

 

判断通道的状态

isRegister

isOpen

blockingLock 获取阻塞锁对象

supportOptions 返回通道支持的Socket Option 

isBlocking

SelectionKey keyFor(selector ) 返回通道向选择器注册的凭证

validOps 返回一个通道支持的操作集

 

SelectorProvider provider() 

SelectorProvider 用于选择器和可选择通道的服务提供者

 

执行connect

connect(SocketAddress )

如果通道处于非阻塞模式,发起连接后,随后某个时间点发起连接;如果是阻塞的,那么立即发起连接,如果连接成功返回真,不成功返回假;

 

如果连接时立即建立的,说明是阻塞的,返回true,而且连接不成功出现异常

如果连接不是立即建立但,返回fasle,那么说明是非阻塞模式,随后必须通过 finishConnect 验证

 

在非阻塞通道下,read和 write 也具有非阻塞特性

 

Selector类

 

多路复用选择器

通过SelectionKey对象 表示通道的注册

 

选择器维护了三个集合

  1. 键集,本身不可修改,通过注册方法注册一个通道,就会增加一个元素,通过keys() 方法返回
  2. 已选择键集,首先 先调用select()方法查看 键集代表的通道是否已经做好了 相关操作准备,如果准备好了 通过 selectedKeys() 方法返回一个 就绪键集,就绪键集始终是键集的一个子集
  3. 已取消键集, 表示已被取消 但通道尚未注销的键 的集合,不可直接访问,在select()方法期间,从键集 中 移除 已取消的键

 

通过已选择键集,或者迭代器的  remove 方法,可以将键 从已选择器中移出。

使用cancel方法能将 键 取消,键会被添加到 已取消键集,在下一次select 操作期间,这个已取消键集中的所有键 会从 全部的键集中移出,并注销该个通道。

 

select () select(long) selectNow()

 

 选择器是线程安全的,但是 选择器的键 和 已选择键集不是线程安全的。

 

select方法一般是阻塞的,它会返回已经就绪的键集数量

面对重复消费的问题,一般采用remove方法 将 键 从 已选择键集 中移出。

 

唤醒操作

wakeup

 

SelectionKey的使用

isValid 方法 测试这个键 是否还有用

选择键包含两个集

interest

ready 表示就绪

 

isAccptable

isConnectable

isReadable

isWritable

 

设置attach 附加

 

Pipe.SinkChannel

Pipe.SourceChannel

 

AIO

AsynchronousFileChannel 是一个读取,写入和操作文件的异步通道

 

通过open方法打开一个文件

异步文件通道在文件没有当前位置,而是将文件位置指定给启动异步操作的每个读取,写入方法

ComletionHandler 被指定为参数,被调用以消耗I/O操作的结果

 

AsynchronousFileChannel.open(path, StandardOpenOption.ENUM)

使用lock() 方法获取文件锁 , 这个方法有 多个重载 

Future <FileLock > future =channel.lock()

FileLock lock=future.lock()

 

lock(A attchment , CompletionHandler<Future ,  ? super A > handler>

CompletionHandler 需要实现两个方法,一个是成功的completed方法,这个方法内需要释放锁;一个是失败的falied方法

 

posted @ 2020-09-29 20:28  lfcom  阅读(155)  评论(0编辑  收藏  举报