netty---------write flush两个方法到底做了什么?
上一篇已经看到:netty的读,是调用unsafe的read方法,把channel中的数据read到byteBuff中的byteBuffer里,也是封装了nio的读。
那么根据猜想,netty的写应该也是调用nio 的 channel的write(byteBuffer),将用户空间的数据,写到内核空间。而且nio的write方法对应的netty应该是flush方法,看看是不是这样。
@Override
-----------ChannelHandlerContext的write方法其实是调用的pipeline的write方法,到最后调用的是tail的write方法,
public final ChannelFuture write(Object msg) {
return tail.write(msg);
}
--------------------这里根据传入的boolean值,决定是write还是writeAndflush,先看write
private void write(Object msg, boolean flush, ChannelPromise promise) {
-----------------因为这里执行的是tail的write方法, 所以要看tail的findContextOutbound的逻辑,tail这个context在初始化的时候inbound是true,但是outbound属性是false,所以要从tail往前,找outboundHandler,而head的outbound属性是true的,看它的write方
法,调用的是unsafe的write方法,是AbstractChannel的write方法。看下一段
AbstractChannelHandlerContext next = findContextOutbound();
final Object m = pipeline.touch(msg, next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
if (flush) {
next.invokeWriteAndFlush(m, promise);
} else {
next.invokeWrite(m, promise);
}
} else {
AbstractWriteTask task;
if (flush) {
task = WriteAndFlushTask.newInstance(next, m, promise);
} else {
task = WriteTask.newInstance(next, m, promise);
}
safeExecute(executor, task, promise, m);
}
}
@Override
-----------------unsafe的write方法
public final void write(Object msg, ChannelPromise promise) {
assertEventLoop();
----------------ChannelOutboundBuffer这个类,维护这一个由他自己的内部类entry组成的一个单链表,entry有着指向byteBuffer和byteBuffer数组的指针,本方法的最下面的addMessage,就是新建一个entry,然后放到链表里,ChannelOutboundBuffer自己有三个属性:
----------------flushedEntry :指向第一个已经被flush的entry
----------------unflushedEntry :指向第一个没有被flush的entry
----------------tailEntry : 队尾的指针。这三个其实很简单
ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;
if (outboundBuffer == null) {
safeSetFailure(promise, WRITE_CLOSED_CHANNEL_EXCEPTION);
ReferenceCountUtil.release(msg);
return;
}
int size;
try {
msg = filterOutboundMessage(msg);
size = pipeline.estimatorHandle().size(msg);
if (size < 0) {
size = 0;
}
} catch (Throwable t) {
safeSetFailure(promise, t);
ReferenceCountUtil.release(msg);
return;
}
outboundBuffer.addMessage(msg, size, promise);
}
所以可以看到,所谓的netty的channelHandlerContext的write方法,其实并不是向内核写入数据,而是把msg放入一个链表中,等待flush,而flush方法也是在headContext中,调用的unsafe的flush方法,
注意这里的unsafe是
@Override
public final void flush() {
assertEventLoop();
ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;
if (outboundBuffer == null) {
return;
}
------------这个方法是把flushedEntry指针置空,把unFlushedEntry指针放到队列头部
outboundBuffer.addFlush();
------------下文
flush0();
}
@Override
-----------------从flush0到这一步的逻辑比较复杂,涉及到各种判断,简单起见,直接看这一步NioSocketChannel的doWriteBytes方法,netty的写,对应的是buf的readBytes,这其实只是方法名字取的问题。回忆之前的doReadBytes对应的是buf的writeBytes方法,
当时是把channel的数据读到nio的ByteBuffer中,现在应该是把byteBuffer中的数据write到channel中了,写到内核
protected int doWriteBytes(ByteBuf buf) throws Exception {
final int expectedWrittenBytes = buf.readableBytes();
return buf.readBytes(javaChannel(), expectedWrittenBytes);
}
---------------还是找到之前的那个byteBuf的实现类,可以看出,还是调用nio的socketChannel的write方法,把tmpBuf(一个Nio的ByteBuffer)写到channel中。
private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
ensureAccessible();
if (length == 0) {
return 0;
} ByteBuffer tmpBuf;
if (internal) {
tmpBuf = internalNioBuffer();
} else {
tmpBuf = buffer.duplicate();
}
tmpBuf.clear().position(index).limit(index + length);
return out.write(tmpBuf);
}
netty---------write flush两个方法到底做了什么?的更多相关文章
- substring()方法到底做了什么?不同版本的JDK中是否有区别?为什么?
该文章是图说Java系列文章中的一篇 substring(int beginIndex, int endIndex)方法在jdk 6和jdk 7中的实现是不同的.了解他们的区别可以帮助你更好的使用 ...
- AFNetworking到底做了什么
写在开头: 作为一个iOS开发,也许你不知道NSUrlRequest.不知道NSUrlConnection.也不知道NSURLSession...(说不下去了...怎么会什么都不知道...)但是你一定 ...
- R语言中将hello打印10次的两种方法
我们有两种方法来做这件事情: 1.for结构 for循环重复的执行一个语句,直到某个变量的值不再包含在序列seq中为止. 语法: for (var in seq) statement 例如: > ...
- 在vc6.0下编的对话框界面如果没做过其他处理,往往显的很生硬,怎么样才能使他有Windows XP的风格呢,其实也很简单,我们来看看下面两种方法。
在vc6.0下编的对话框界面如果没做过其他处理,往往显的很生硬,怎么样才能使他有Windows XP的风格呢,其实也很简单,我们来看看下面两种方法. 方法一: 1.首先确认你在Windows ...
- AFNetworking到底做了什么?(二)
接着上一篇的内容往下讲,如果没看过上一篇内容可以点这: AFNetworking到底做了什么? 之前我们讲到NSUrlSession代理这一块: 代理8: /* task完成之后的回调,成功和失败 ...
- CSS-animations和transitions性能:浏览器到底做了什么?
CSS animations 和 transitions 的性能:浏览器到底做了什么?(译) 原文地址:http://blogs.adobe.com/webplatform/2014/03/18/cs ...
- Java中随机数生成的两种方法,以及math的floor
1.Math的random方法,调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间,返回值是一个伪随机选 ...
- Linux添加系统调用的两种方法
前言 系统调用的基本原理 系统调用其实就是函数调用,只不过调用的是内核态的函数,但是我们知道,用户态是不能随意调用内核态的函数的,所以采用软中断的方式从用户态陷入到内核态.在内核中通过软中断0X80, ...
- java-IO流-字节流-概述及分类、FileInputStream、FileOutputStream、available()方法、定义小数组、BufferedInputStream、BufferedOutputStream、flush和close方法的区别、流的标准处理异常代码
1.IO流概述及其分类 * 1.概念 * IO流用来处理设备之间的数据传输 * Java对数据的操作是通过流的方式 * Java用于操作流的类都在IO包中 * ...
随机推荐
- 2018JavaScript状态调查:5个重要的思考( import takeaways) (摘译)
英文原文 (内有视频). 以下是翻译和摘录. 最近JS状态调查结构出来了,如果你关心网页开发,你会关心这些结果. 本文探索5个takeaways并总结这些结论. 1. JavaScript Had ...
- Vue.js示例:树型视图; 模式组件;
树型图 本示例是一个简单的树形视图实现,它展现了组件的递归使用. mycode pen:https://codepen.io/chentianwei411/pen/KGKQxE 重点:递归是如何形成的 ...
- 进程状态TASK_UNINTERRUPTIBLE
进程拥有以下几种状态:就绪/运行状态.等待状态(可以被中断打断).等待状态(不可以被中断打断).停止状态和僵死状态. TASK_RUNNING: 正在运行或处于就绪状态:就绪状态是指进程申请到了CPU ...
- 【洛谷p2312】解方程
(清明培训qwq,明天就要回学校了qwq拒绝) 行吧我洛谷都四天没碰了 解方程[传送门] 算法标签: (作为一个提高+省选-的题) 丁大佬真的很有幽默感emmm: #include <cstdi ...
- 『MXNet』第四弹_Gluon自定义层
一.不含参数层 通过继承Block自定义了一个将输入减掉均值的层:CenteredLayer类,并将层的计算放在forward函数里, from mxnet import nd, gluon from ...
- Excel中如何匹配另外一个Excel中的数据
场景: 我在Excel中想展示通过一列匹配到另外Excel中的数据.对于程序员来说,就是left join 出 B表的数据. 但是在Excel中怎么做呢,我又不想每次都在把数据导入到数据库中操作. 这 ...
- Mybatis自动生成实体类,映射文件,dao
http://www.mybatis.org/generator/index.html 方法一:eclipse插件式 1.下载 mybatis-generator-core-1.3.2.jar 解压后 ...
- C语言实现哈夫曼编码(最小堆,二叉树)
// 文件中有通过QT实现的界面#include <stdio.h> #include <stdlib.h> #include <string.h> typedef ...
- 基于TcpListerer的web服务器 和 基于HttpListerer的web服务器
摘自<Asp.Net 本质论>作者:郝冠军 /* 为了简化基于TCP协议的监听程序,.NET在System.Net.Sockets命名空间中提供了TcpListerer类,使用它,在构造函 ...
- vue数组操作不更新视图问题
vue 观察数组的变异方法 更新视图 push() pop() shift() unshift() splice(i,n,arr) sort(xx) reverse() ex: app.book.pu ...