【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函数
@Override
protected 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 ...
随机推荐
- POJ2135:Farm Tour
题意:给定一个无向图,从1走到n再从n走回1,每个边只能走一遍,求最短路 题解:可以定义一个源点s,和一个汇点t s和1相连容量为2,费用为0, t和n相连容量为2,费用为0 然后所用的边的容量都定为 ...
- 【SPOJ839】Optimal Marks 网络流
You are given an undirected graph G(V, E). Each vertex has a mark which is an integer from the range ...
- 习题9-4 uva 1630
题意: 给你一串数字,要求你对其进行折叠使其长度最短. 折叠情况:全是一个字母 & 重复的字符串 AAAAAAAAAABABABCCD --> 9(A)3(AB)CCD NEE ...
- 基于Android的高校饮水宝app
这是一个高校饮用水配送项目,是一个毕业设计,去年的,包括了服务端和客户端,是一个不错的项目,分享一下: 随着通讯行业的迅猛发展,我国的手机用户也在不断的增加.据信息部的统计数据显示,我国已有接近7. ...
- Qone 正式开源,使 javascript 支持 .NET LINQ
Qone 下一代 Web 查询语言,使 javascript 支持 LINQ Github: https://github.com/dntzhang/qone 缘由 最近刚好修改了腾讯文档 Excel ...
- 原生js实现preAll和nextAll方法
一直以来都在好奇,jquery的prevAll和nextAll方法都是咋实现的,那么厉害,而且还那么方便.不得不说,jquery真的帮我们省去了开发中手写大量js代码带来的开发进度问题,而且很好的解决 ...
- Java获取随机数的3种方法
最小值---最大值(整数)的随机数 方法1 (数据类型)(最小值+Math.random()*(最大值-最小值+1)) 例: (int)(1+Math.random()*(10-1+1)) / ...
- Windows转Linux总结(附带常用Linux命令-LinuxMint)
这是我在Linux系统下写的第一篇博客,花了一周的时间从Windows系统转到Linux并且可以完成日常操作,能在Linux系统下完成开发,运用各种开发工具,写各种语言小程序和JavaEE. 经过这一 ...
- JMQ
[京东技术]京东的MQ经历了JQ->AMQ->JMQ的发展,其中JQ的基于关系数据库,严格意义上讲称不上消息中间件,JMQ的存储是JFS和HBase,AMQ即ActiveMQ,本文说说JM ...
- Mobx使用详解
Mobx是一个功能强大,上手非常容易的状态管理工具.就连redux的作者也曾经向大家推荐过它,在不少情况下你的确可以使用Mobx来替代掉redux. 本教程旨在介绍其用法及概念,并重点介绍其与Reac ...