【Netty源码分析】发送数据过程
来源:互联网 发布:车载蓝牙播放器 知乎 编辑:程序博客网 时间:2024/05/22 03:39
前面两篇博客【Netty源码分析】Netty服务端bind端口过程和【Netty源码分析】客户端connect服务端过程中我们分别介绍了服务端绑定端口和客户端连接到服务端的过程,接下来我们分析一下数据发送的过程。
future.channel().writeAndFlush("Hello Netty Server ,I am a common client");调用AbstractChannel的writeAndFlush函数
@Overridepublic ChannelFuture writeAndFlush(Object msg) { return pipeline.writeAndFlush(msg);}
@Overridepublic final ChannelFuture writeAndFlush(Object msg) { return tail.writeAndFlush(msg);}
调用AbstractChannelHandlerContext的writeAndFlush函数
@Overridepublic ChannelFuture writeAndFlush(Object msg) { return writeAndFlush(msg, newPromise());}
@Overridepublic 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函数
@Overridepublic void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { unsafe.write(msg, promise);}AbstractUnsafe中调用write函数,这一步就可以认为将数据写到buffer中了,接下来buffer的东西我们会分析。
@Overridepublic 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过程
@Overridepublic void flush(ChannelHandlerContext ctx) throws Exception { unsafe.flush();}
AbstractUnsafe中调用flush过程,在这里我们可以看到之前写入数据的buffer(outboundBuffer)
@Overridepublic final void flush() { assertEventLoop(); ChannelOutboundBuffer outboundBuffer = this.outboundBuffer; if (outboundBuffer == null) { return; } outboundBuffer.addFlush(); flush0();}调用AbstractNioUnsafe的flush0函数
@OverrideAbstractUnsafe中调用flush0函数protected void flush0() {........ doWrite(outboundBuffer);....... }
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; } } }
0 0
- 【Netty源码分析】发送数据过程
- 【Netty源码分析】数据读取过程
- 【Netty源码分析】客户端connect服务端过程
- 【Netty源码分析】Netty服务端bind端口过程
- openWrt: 数据发送过程分析
- muduo源码分析--数据发送
- netty源码分析(十九)Netty项目开发过程中常见且重要事项分析
- Netty学习6-ChanelHandler【2】调用过程源码分析
- Netty启动过程分析
- Netty 源码分析
- netty源码分析小结
- netty 源码分析一
- netty 源码分析二
- netty源码分析
- Netty源码分析
- netty源码分析一
- 【Netty】源码分析目录
- Netty源码分析:NioEventLoopGroup
- Activity生命周期
- 序列化和反序列化
- TensorFlow学习资源
- 关于项目调试的问题
- Egit fetch from upstream 与 pull的区别
- 【Netty源码分析】发送数据过程
- 非比较排序学习
- 3、编写一个程序,从键盘上输入学生的三门课程成绩,求总成绩和平均成绩。
- Java连接Oracle数据库简单实例
- tomcat startup.sh启动没有日志输出
- SQL server 事务与锁
- spark standalone模式 环境搭建
- opencv矩阵常用操作(一)
- diffcount.exe