【Netty源码分析】发送数据过程
前面两篇博客【Netty源码分析】Netty服务端bind端口过程和【Netty源码分析】客户端connect服务端过程中我们分别介绍了服务端绑定端口和客户端连接到服务端的过程,接下来我们分析一下数据发送的过程。
future.channel().writeAndFlush("Hello Netty Server ,I am a common client");
调用AbstractChannel的writeAndFlush函数
@Override public ChannelFuture writeAndFlush(Object msg) { return pipeline.writeAndFlush(msg); }
@Override public final ChannelFuture writeAndFlush(Object msg) { return tail.writeAndFlush(msg); }
调用AbstractChannelHandlerContext的writeAndFlush函数
@Override public ChannelFuture writeAndFlush(Object msg) { return writeAndFlush(msg, newPromise()); }
@Override public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { ........ write(msg, true, promise); ....... }
需要注意的一点是,写数据的过程其实是分为两步的,第一步是将要写的数据写到buffer中,第二步是flush其实就是从buffer中读取数据然后发送给服务端。
private void invokeWriteAndFlush(Object msg, ChannelPromise promise) { if (invokeHandler()) { invokeWrite0(msg, promise); invokeFlush0(); } else { writeAndFlush(msg, promise); } }
首先是调用write函数,将数据写到buffer中。
private void invokeWrite0(Object msg, ChannelPromise promise) { try { ((ChannelOutboundHandler) handler()).write(this, msg, promise); } catch (Throwable t) { notifyOutboundHandlerException(t, promise); } }
调用HeadContext的write函数
@Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { unsafe.write(msg, promise); }
AbstractUnsafe中调用write函数,这一步就可以认为将数据写到buffer中了,接下来buffer的东西我们会分析。
@Override public final void write(Object msg, ChannelPromise promise) { ....... outboundBuffer.addMessage(msg, size, promise); ...... }
接下来是flush过程,将数据写到服务端
private void invokeFlush0() { try { ((ChannelOutboundHandler) handler()).flush(this); } catch (Throwable t) { notifyHandlerException(t); } }
HeadContext中调用flush过程
@Override public void flush(ChannelHandlerContext ctx) throws Exception { unsafe.flush(); }
AbstractUnsafe中调用flush过程,在这里我们可以看到之前写入数据的buffer(outboundBuffer)
@Override public final void flush() { assertEventLoop(); ChannelOutboundBuffer outboundBuffer = this.outboundBuffer; if (outboundBuffer == null) { return; } outboundBuffer.addFlush(); flush0(); }
调用AbstractNioUnsafe的flush0函数
@Overrideprotected void flush0() { ........ doWrite(outboundBuffer); ....... }
AbstractUnsafe中调用flush0函数
protected void flush0() { ........ doWrite(outboundBuffer); ....... }
调用NioSocketChannel中的doWrite函数,在doWrite函数中会看到调用NIO中的socketChannel中的写数据操作。
@Override protected void doWrite(ChannelOutboundBuffer in) throws Exception { for (;;) { int size = in.size(); if (size == 0) { // All written so clear OP_WRITE clearOpWrite(); break; } long writtenBytes = 0; boolean done = false; boolean setOpWrite = false; // Ensure the pending writes are made of ByteBufs only. ByteBuffer[] nioBuffers = in.nioBuffers(); int nioBufferCnt = in.nioBufferCount(); long expectedWrittenBytes = in.nioBufferSize(); SocketChannel ch = javaChannel(); // Always us nioBuffers() to workaround data-corruption. // See https://github.com/netty/netty/issues/2761 switch (nioBufferCnt) { case 0: // We have something else beside ByteBuffers to write so fallback to normal writes. super.doWrite(in); return; case 1: // Only one ByteBuf so use non-gathering write ByteBuffer nioBuffer = nioBuffers[0]; for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) { final int localWrittenBytes = ch.write(nioBuffer); if (localWrittenBytes == 0) { setOpWrite = true; break; } expectedWrittenBytes -= localWrittenBytes; writtenBytes += localWrittenBytes; if (expectedWrittenBytes == 0) { done = true; break; } } break; default: for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) { final long localWrittenBytes = ch.write(nioBuffers, 0, nioBufferCnt); if (localWrittenBytes == 0) { setOpWrite = true; break; } expectedWrittenBytes -= localWrittenBytes; writtenBytes += localWrittenBytes; if (expectedWrittenBytes == 0) { done = true; break; } } break; } // Release the fully written buffers, and update the indexes of the partially written buffer. in.removeBytes(writtenBytes); if (!done) { // Did not write all buffers completely. incompleteWrite(setOpWrite); break; } } }
【Netty源码分析】发送数据过程的更多相关文章
- Netty源码剖析-发送数据
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! 开始之前先介绍下Netty写数据的三种方式: ①:write:写到一 ...
- 【Netty源码分析】数据读取过程
首先客户端连接到服务端时服务端会开启一个线程,不断的监听客户端的操作.
- Netty源码分析第5章(ByteBuf)---->第10节: SocketChannel读取数据过程
Netty源码分析第五章: ByteBuf 第十节: SocketChannel读取数据过程 我们第三章分析过客户端接入的流程, 这一小节带大家剖析客户端发送数据, Server读取数据的流程: 首先 ...
- Netty源码分析第7章(编码器和写数据)---->第1节: writeAndFlush的事件传播
Netty源码分析第七章: 编码器和写数据 概述: 上一小章我们介绍了解码器, 这一章我们介绍编码器 其实编码器和解码器比较类似, 编码器也是一个handler, 并且属于outbounfHandle ...
- Netty源码分析第7章(编码器和写数据)---->第5节: Future和Promies
Netty源码分析第七章: 编码器和写数据 第五节: Future和Promise Netty中的Future, 其实类似于jdk的Future, 用于异步获取执行结果 Promise则相当于一个被观 ...
- Netty源码分析 (七)----- read过程 源码分析
在上一篇文章中,我们分析了processSelectedKey这个方法中的accept过程,本文将分析一下work线程中的read过程. private static void processSele ...
- Netty源码分析第7章(编码器和写数据)---->第2节: MessageToByteEncoder
Netty源码分析第七章: Netty源码分析 第二节: MessageToByteEncoder 同解码器一样, 编码器中也有一个抽象类叫MessageToByteEncoder, 其中定义了编码器 ...
- 【Netty源码分析】客户端connect服务端过程
上一篇博客[Netty源码分析]Netty服务端bind端口过程 我们介绍了服务端绑定端口的过程,这一篇博客我们介绍一下客户端连接服务端的过程. ChannelFuture future = boos ...
- Netty源码分析第7章(编码器和写数据)---->第3节: 写buffer队列
Netty源码分析七章: 编码器和写数据 第三节: 写buffer队列 之前的小节我们介绍过, writeAndFlush方法其实最终会调用write和flush方法 write方法最终会传递到hea ...
随机推荐
- ●BZOJ 4566 [Haoi2016]找相同字符
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4566题解: 广义后缀自动机 对两个串同时建立一个广义后缀自动机. 同时统计出每个状态对两个串 ...
- [Apio2012]dispatching 左偏树
题目描述 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都有且仅有一个上级.为保密,同时增 ...
- [SPOJ 287] Smart Network Administrator 二分答案+网络流
The citizens of a small village are tired of being the only inhabitants around without a connection ...
- 17.10.28&29
28上午 骚猪选讲 28下午 BOZJ 1081 [SCOI2005]超级格雷码 感觉就是一个找规律,然后模拟输出.半天没找到一个比较简便的模拟方法,这份代码是学习网上一位大佬的,很巧妙. 代码: # ...
- 2015 多校联赛 ——HDU5353(构造)
Each soda has some candies in their hand. And they want to make the number of candies the same by do ...
- [bzoj4828][Ah/Hnoi2017]大佬
来自FallDream的博客,未经允许,请勿转载,谢谢. 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你 ...
- 测试修改gcs_server_processes参数
RAC部署前提是要求各节点的主机硬件一致的,但实际如果碰上一些不规范的客户,经费有限或是扩容时已买不到同样的机器,那么采购的机器会有一些区别,比如RAC各节点的CPU核数有区别,那么默认的gcs_se ...
- widows下的进程与服务
进程: 当程序卡死的时候,我们可以直接通过任务管理器来关闭进程. 服务: 在这个界面,我们可以选择启动或者关闭相关服务,还可以选择服务是否自动启动. 以关闭MySQL自启动服务为例:https://j ...
- sql server 表分区
背景: 一般情况下,我们建立数据库表时,表数据都存放在一个文件里. 但是如果是分区表的话,表数据就会按照你指定的规则分放到不同的文件里,把一个大的数据文件拆分为多个小文件,还可以把这些小文件放在不同的 ...
- spring cloud 入门系列二:使用Eureka 进行服务治理
服务治理可以说是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册和发现. Spring Cloud Eureka是Spring Cloud Netflix 微服务套件的一部分 ...