Netty:options和configs

在使用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

DefaultChannelConfig中是一般性的选项,NioSocketChannelConfig是与socket相关的设置,ChannelOption中以SO开头的都是与此相关的。
使用相关option时,也是通过config的getOption去获取的。当然Config对象也设置了一些属性,和这些option相关联,可以通过方法直接访问到。

    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()获取设置,然后启动定时任务,等待超时。



Netty是一个高性能、异步事件驱动的网络应用框架,特别适合用于构建高并发的服务器客户端应用程序,包括UDP协议的支持。如果你想要在Netty中使用UDP进行多播(Multicast)通信,以下是一些关键步骤: 1. **创建MultiCastGroup**: 首先,你需要获取一个多播组地址,例如`InetAddress.getByName("224.0.0.1")`,这个例子是针对所有路由器组(Link-Local Multicast)。 2. **配置DatagramPacketFactory**: 创建一个`DatagramPacketFactory`实例,用于构建包含多播组信息的数据包。 ```java DatagramPacketFactory factory = new DefaultDatagramPacketFactory(); byte[] buffer = new byte[1024]; DatagramPacket packet = factory.newDatagram(buffer, buffer.length, multicastGroup); ``` 3. **设置SocketOptions**: 在`Bootstrap`或`ChannelInitializer`中,设置`DatagramChannel`的相关选项,如接收时间戳多播组套接字计数器。 ```java ChannelConfig config = channel.config(); config.setOption(ChannelOption.SO_REUSEADDR, true); config.setOption(ChannelOption.SO_BROADCAST, true); config.setOption(ChannelOption.IP_MULTICAST_LOOP, true); // 发送时回环到本机 config.setOption(ChannelOption.IP_TTL, (short) 2); // 设置TTL值,通常2-3,防止无限传播 config.setOption(ChannelOption.IP_ADD_MEMBERSHIP, InetAddressUtil.getByName(multicastGroup.getHostAddress())); ``` 4. **创建Handler**: 编写一个处理多播数据包的处理器,比如`MulticastHandler`或自定义处理器。 5. **绑定端口并开始监听**: 最后,通过`Bootstrap`绑定端口并启动接受多播数据。 ```java Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(DatagramChannel.class) .handler(new MulticastHandler(packet)) .connect(multicastGroup.getPort()) .sync() .channel(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bdmh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值