转载

Netty 学习系列一:Java NIO 预备知识

Netty 学习系列一:Java NIO 预备知识

一、TCP发送缓冲区/TCP接收缓冲区

在传输层,每个socket对应的TCP连接都拥有自己的接收缓冲区和发送缓冲区。

接收缓冲区:用于存储网络层发往当前TCP连接的分组数据,直到应用层将数据从其中取走。

发送缓冲区:用于存储当前TCP连接即将发送给对端的分组数据,直到收到对端的接收确认。

TCP发送缓冲区和接收缓冲区用于实现TCP协议的“滑动窗口”和“流量控制”功能,保证TCP的可靠传输。

二、socket中read/write的语义

1、SocketChannel.read(ByteBuffer dest)

阻塞模式下:阻塞直到“TCP接收缓冲区”中有数据可读,并且成功将数据读取到了应用进程ByteBuffer中。

非阻塞模式下:尝试从“TCP接收缓冲区”中读取当前可读的数据,不论是否能读取到数据均立即返回。

2、SocketChannel.write(ByteBuffer src)

阻塞模式下:阻塞直到ByteBuffer src中的数据全部成功写入“TCP发送缓冲区”中。

非阻塞模式下:尝试将ByteBuffer src中的数据写入“TCP发送缓冲区”中,不保证数据全部写入(如果“TCP发送缓冲区”中空间不足,也可能写入部分数据),然后立即返回。

三、SelectionKey的operation语义

OP_READ:“TCP接收缓冲区”中有了新的可读数据。

OP_WRITE:“TCP发送缓冲区”中可以写入新的数据了。

OP_CONNECT:“TCP三次握手”完成。

OP_ACCEPT:新的客户端socket连接建立完成,放入了服务端“已完成连接队列”。

四、Direct ByteBuffer和Non-Direct ByteBuffer

1、概述

Non-Direct ByteBuffer的内存是分配在堆上的,可以把它想象成一个字节数组的包装类,直接由JVM负责垃圾收集。

Direct ByteBuffer是通过JNI在JVM外的内存空间分配的,该内存块并不直接由JVM负责垃圾回收,而是在Direct ByteBuffer包装类被回收时,通过Java reference机制来释放该内存块。

2、网络读写

操作系统无法直接操作用户空间的ByteBuffer,socket在调用read/write进行网络读写操作时,会先把用户空间的Non-direct ByteBuffer转换为操作系统内核空间的临时Direct ByteBuffer(这个过程需要进行内存拷贝),然后再进行相关的操作。

如果直接将用户进程的数据存储在Direct ByteBuffer中,则可以节省两次内存拷贝的时间。然后构造和析构临时Direct ByteBuffer的时间和代价比较长,因此一般对Direct ByteBuffer进行池化处理。

原文  https://xiaozhuanlan.com/topic/5631720489
正文到此结束
Loading...