netty中的write方法
io.netty.channel.Channel write方法
//注意这个chnnel是netty中的chinnel,不是nio中的channel
io.netty.channel.Channel
/**
* Request to write a message via this {@link Channel} through the {@link ChannelPipeline}.
* This method will not request to actual flush, so be sure to call {@link #flush()}
* once you want to request to flush all pending data to the actual transport.
* 请求通过ChannelPipeline由Channel写消息。 此方法不会请求不会flush,因此一旦您要请求将所有待处理数据刷新到实际传输,请务必调用flush()。
*/
ChannelFuture write(Object msg);
/**
* Shortcut for call {@link #write(Object)} and {@link #flush()}.
*/
ChannelFuture writeAndFlush(Object msg);
//AbstractChannel 类
//由此可知 channel.write()方法实际上是调用的ChannelPipeline的write方法
@Override
public ChannelFuture write(Object msg) {
return pipeline.write(msg);
}
io.netty.channel.ChannelPipeline
ChannelFuture
- The result of an asynchronous Channel I/O operation.(异步channel I/O操作的结果)
可以判断是否完成 isDone(), 是否成功 isSuccess()等
可以添加监听器 addListener 当操作完成后执行监听器
为什么netty的写是异步的呢? 返回给你一个ChannelFuture
- 在java nio中 channel.write (buffer);
Java NIO (中文版) 书中Channel 的 read( ) 和 write( )方法使用 ByteBuffer 对象作为参数。两种方法均返回已传输的字节数,可能比缓冲区的字节数少甚至可能为零
这就是说,我们在write的时候不一定能写入数据.比如说socket的另一端阻塞了,就写不了数据了.
调用nio Channel 的 write就一直会返回0.所以在netty中,我们写入的东西都会存在一个地方,把 <
要写入的东西
,ChannelFuture
>绑定起来,
当要写入的东西
完全被写入后,ChannelFuture就会被设为success,如果有监听器的话,会执行用户写的监听器.
netty中存放<要写入的东西
,ChannelFuture
>的是ChannelOutboundBuffer类
AbstractChannel 类
//AbstractChannel 类
@Override
//把<要写入的东西,ChannelFuture> 关联起来
public final void write(Object msg, ChannelPromise promise) {
ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;
if (outboundBuffer == null) {
// If the outboundBuffer is null we know the channel was closed and so
// need to fail the future right away. If it is not null the handling of the rest
// will be done in flush0()
// See https://github.com/netty/netty/issues/2362
safeSetFailure(promise, CLOSED_CHANNEL_EXCEPTION);
// release message now to prevent resource-leak
ReferenceCountUtil.release(msg);
return;
}
//把<要写入的东西,ChannelFuture> 关联起来
outboundBuffer.addMessage(msg, size, promise);
ChannelOutboundBuffer 类
* (传输实现者) AbstractChannel使用的一个内部的结构来 存储它的待发送请求
* 所有方法都必须由I / O线程的传输实现调用,但以下方法除外:
* size()和isEmpty()
*
*/
public final class ChannelOutboundBuffer {
//java nio 写了多少个字节,你就来这里面找 已经写入的 **要写入的东西**
//并调用ChannelFuture的 setSuccess方法
public void removeBytes(long writtenBytes) {
for (;;) {
Object msg = current();
if (!(msg instanceof ByteBuf)) {
assert writtenBytes == 0;
break;
}
final ByteBuf buf = (ByteBuf) msg;
final int readerIndex = buf.readerIndex();
final int readableBytes = buf.writerIndex() - readerIndex;
if (readableBytes <= writtenBytes) {
if (writtenBytes != 0) {
progress(readableBytes);
writtenBytes -= readableBytes;
}
//把写入完成的 **要写入的东西** ChannelFuture设置为成功
remove();
//把写入完成的 **要写入的东西** ChannelFuture设置为成功
private static void safeSuccess(ChannelPromise promise) {
if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
}
}
后记
- 需要探索的地方
- ChannelOutboundBuffer 里面没有被写出的字节不能太大了,在写的时候如果发现这个ChannelOutboundBuffer 太大了,可以停止去写.
学习具体API
- 注意 ChannelFuture的监听器,不能太耗时,也不能死锁,因为它毕竟是在I/O线程里面被调用的.
验证具体API
- 如果ChannelFuture