Netty的深入浅出--35.零拷贝实例剖析

下面写两个程序一个基于IO的,一个基于NIO的。将两个进行对比看出优劣;

对比方法:客户端不断的从磁盘中读取数据到服务端,服务端收到数据之后丢弃。最后对比两种方式所消耗的时间。

IO操作:

服务端:

Netty的深入浅出--35.零拷贝实例剖析

客户端:

Netty的深入浅出--35.零拷贝实例剖析

 启动服务端:

Netty的深入浅出--35.零拷贝实例剖析

启动客户端:

运行很多次之后,发现耗时基本上停留在400多毫秒

Netty的深入浅出--35.零拷贝实例剖析

 

NIO:

服务端:

这里设置了一个socket属性:

Netty的深入浅出--35.零拷贝实例剖析

我们查看一下它的源码 的dom说明:

Netty的深入浅出--35.零拷贝实例剖析

该方法是禁用或者启动SocketOptions这个属性

Netty的深入浅出--35.零拷贝实例剖析

描述的是:在连接关闭之后,但是tcp连接可能处于的是一种超时的状态,这种状态称为一种time_wait状态

Netty的深入浅出--35.零拷贝实例剖析

 当处于上面所说的time_wait之后,是不能绑定到这个socke端口号上的。一但尝试绑定就会报这个地址已经被占用的警告。因为虽然断开了连接,但是还是只是处于一种超时的状态,没有释放掉这个socket端口号,简单来说就是:占着坑位,不过干事。

Netty的深入浅出--35.零拷贝实例剖析

 所以说,当我们使用了setreuseaddress方法之后,我们就可以使用这种处于time_out状态下的端口号了

Netty的深入浅出--35.零拷贝实例剖析

当连接上之后会获得一个通道:

Netty的深入浅出--35.零拷贝实例剖析

accept方法的dom源码:

Netty的深入浅出--35.零拷贝实例剖析

如果是非阻塞的话,在未连接的情况下返回时null

如果是阻塞的话,在未连接的情况下会一直阻塞式等待连接

Netty的深入浅出--35.零拷贝实例剖析

不过它返回的socket方法,一定是阻塞模式的

Netty的深入浅出--35.零拷贝实例剖析

它默认情况下都是阻塞的,如果我们不设置其实也是可以的,但是如果有selector的话,一定要使用非阻塞的。

Netty的深入浅出--35.零拷贝实例剖析

 将数据读到bytebuffer当中:

Netty的深入浅出--35.零拷贝实例剖析

现在我们需要重新将bytebuffer的position和limit位置回到初始位(之前我们采用的是clear或者flip两种方式):

Netty的深入浅出--35.零拷贝实例剖析

查看rewind方法源码:

Netty的深入浅出--35.零拷贝实例剖析

客户端:

获取socketChannel对象

Netty的深入浅出--35.零拷贝实例剖析

向服务器端发起连接:

Netty的深入浅出--35.零拷贝实例剖析 

 在之前使用selector管理channel的时候,我们设置的是非阻塞的,现在由于只有一个客户端,而且并没有使用selector,所以我们直接使用阻塞式就可以了

Netty的深入浅出--35.零拷贝实例剖析

获取文件通道

Netty的深入浅出--35.零拷贝实例剖析 

第一个方法transferFrom:将数据读到channel通道中来

第二个方法transferTo:将数据写到writeByteChannel中去;

Netty的深入浅出--35.零拷贝实例剖析 

 然后传递到socketChannel;

返回的是实际传递的数量

Netty的深入浅出--35.零拷贝实例剖析

 查看transferTo方法源码:

将传递的字节放入到能够写的byte channel中

Netty的深入浅出--35.零拷贝实例剖析

 如果采用的是非阻塞的形式的话,读取的字节数量会相比更少:

Netty的深入浅出--35.零拷贝实例剖析

重点:这个方法比我们之前使用循环不断从filechannel中读取数据效率更高 !

Netty的深入浅出--35.零拷贝实例剖析

重点:在一些操作系统中直接将字节传送到文件系统缓存中,而不是去先将他们复制一份。这就是之前说的零拷贝。

Netty的深入浅出--35.零拷贝实例剖析 

打印:

Netty的深入浅出--35.零拷贝实例剖析 

启动服务器:

Netty的深入浅出--35.零拷贝实例剖析 

启动客户端:

Netty的深入浅出--35.零拷贝实例剖析 

 对比之前IO耗时,发现性能上效率上提高了很多。