标签:
在使用Netty时,初始化服务端或客户端时,我们经常会看到如下代码
Bootstrap b = new Bootstrap(); ...... b.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true);通过option方法设置一些选项(参数),它其实是一个Map,维护这键值对,option方法在AbstractBootstrap类中
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>(); @SuppressWarnings("unchecked") public <T> B option(ChannelOption<T> option, T value) { if (option == null) { throw new NullPointerException("option"); } if (value == null) { synchronized (options) { options.remove(option); } } else { synchronized (options) { options.put(option, value); } } return (B) this; }如果value是null,就会从options中删除这个对象,我们之前传入的ChannelOption.TCP_NODELAY,作为key值,true 作为value值。
ChannelOption有很多选项可以设置,具体可以参见Netty文档http://netty.io/4.1/api/io/netty/channel/ChannelOption.html
当我们要使用设置好的option时,其实是通过Channel的Config去访问的,那我们设置的option是怎样写入Config的呢?以NioSocketChannel为例,初始化时
public NioSocketChannel(Channel parent, SocketChannel socket) { super(parent, socket); config = new NioSocketChannelConfig(this, socket.socket()); }这里会创建一个NioSocketChannelConfig对象,然后在BootStrap的init方法中,有这样的过程
@Override @SuppressWarnings("unchecked") void init(Channel channel) throws Exception { ChannelPipeline p = channel.pipeline(); ...... final Map<ChannelOption<?>, Object> options = options(); synchronized (options) { for (Entry<ChannelOption<?>, Object> e: options.entrySet()) { try { if (!channel.config().setOption((ChannelOption<Object>) e.getKey(), e.getValue())) { logger.warn("Unknown channel option: " + e); } } catch (Throwable t) { logger.warn("Failed to set a channel option: " + channel, t); } } } ...... }我们看到,它遍历channe的options,然后通过config对象的setOption去设置config中的属性,如DefaultChannelConfig中
@Override @SuppressWarnings("deprecation") public <T> boolean setOption(ChannelOption<T> option, T value) { validate(option, value); if (option == CONNECT_TIMEOUT_MILLIS) { setConnectTimeoutMillis((Integer) value); } else if (option == MAX_MESSAGES_PER_READ) { setMaxMessagesPerRead((Integer) value); } else if (option == WRITE_SPIN_COUNT) { setWriteSpinCount((Integer) value); } else if (option == ALLOCATOR) { setAllocator((ByteBufAllocator) value); } else if (option == RCVBUF_ALLOCATOR) { setRecvByteBufAllocator((RecvByteBufAllocator) value); } else if (option == AUTO_READ) { setAutoRead((Boolean) value); } else if (option == AUTO_CLOSE) { setAutoClose((Boolean) value); } else if (option == WRITE_BUFFER_HIGH_WATER_MARK) { setWriteBufferHighWaterMark((Integer) value); } else if (option == WRITE_BUFFER_LOW_WATER_MARK) { setWriteBufferLowWaterMark((Integer) value); } else if (option == MESSAGE_SIZE_ESTIMATOR) { setMessageSizeEstimator((MessageSizeEstimator) value); } else { return false; } return true; }DefaultSocketChannelConfig中道理一样。
NioSocketChannelConfig的继承关系如下
NioSocketChannelConfig extends DefaultSocketChannelConfig extends DefaultChannelConfig implements ChannelConfig
public <T> T getOption(ChannelOption<T> option) { if (option == null) { throw new NullPointerException("option"); } if (option == CONNECT_TIMEOUT_MILLIS) { return (T) Integer.valueOf(getConnectTimeoutMillis()); } ...... return null; }比如我们设置超时时间ChannelOption.CONNECT_TIMEOUT_MILLIS,那么在AbstractNioChannel的connect方法中就能看到它的踪影:
public final void connect( ...... try { ...... boolean wasActive = isActive(); if (doConnect(remoteAddress, localAddress)) { fulfillConnectPromise(promise, wasActive); } else { connectPromise = promise; requestedRemoteAddress = remoteAddress; // Schedule connect timeout. int connectTimeoutMillis = config().getConnectTimeoutMillis(); if (connectTimeoutMillis > 0) { connectTimeoutFuture = eventLoop().schedule(new OneTimeTask() { @Override public void run() { ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise; ConnectTimeoutException cause = new ConnectTimeoutException("connection timed out: " + remoteAddress); if (connectPromise != null && connectPromise.tryFailure(cause)) { close(voidPromise()); } } }, connectTimeoutMillis, TimeUnit.MILLISECONDS); } ...... } } catch (Throwable t) { promise.tryFailure(annotateConnectException(t, remoteAddress)); closeIfClosed(); } }config().getConnectTimeoutMillis()获取设置,然后启动定时任务,等待超时。
标签:
原文地址:http://blog.csdn.net/bdmh/article/details/50051643