Netty UDP 報文截取問題
問題
- 最近在寫一個 syslog udp 日志接收器,然后發(fā)現(xiàn)接收過大的日志數(shù)據(jù)會被截斷,拿到的信息不完整
源碼追蹤
創(chuàng)建 udp server 的示例代碼
def b = new Bootstrap()
group = new NioEventLoopGroup()
b.group(group)
.channel(NioDatagramChannel.class)
.localAddress(config.udp.port)
.handler(new ChannelInitializer<DatagramChannel>() {
@Override
protected void initChannel(DatagramChannel datagramChannel) throws Exception {
ChannelPipeline channelPipeline = datagramChannel.pipeline()
channelPipeline.addLast(
new UDPSyslogMessageDecoder(),
new SyslogMessageHandler()
)
if (config.log) {
channelPipeline.addLast(new SyslogMessageLogHandler())
}
channelPipeline.addLast(new QianxinLogHandler(vertx,config))
}
})
startFuture = b.bind().sync()
NioDatagramChannel 初始化源碼追蹤
channel 使用 NioDatagramChannel ,追蹤 NioDatagramChannel 源碼
- 初始化
NioDatagramChannel
io.netty.channel.socket.nio.NioDatagramChannel.NioDatagramChannel()
public NioDatagramChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
- 調(diào)用構(gòu)造方法
io.netty.channel.socket.nio.NioDatagramChannel#NioDatagramChannel(java.nio.channels.DatagramChannel)
public NioDatagramChannel(DatagramChannel socket) {
super(null, socket, SelectionKey.OP_READ);
config = new NioDatagramChannelConfig(this, socket);
}
- 初始化
NioDatagramChannelConfig配置信息
io.netty.channel.socket.nio.NioDatagramChannelConfig.NioDatagramChannelConfig
NioDatagramChannelConfig(NioDatagramChannel channel, DatagramChannel javaChannel) {
super(channel, javaChannel.socket());
this.javaChannel = javaChannel;
}
- 調(diào)用父類構(gòu)造方法
io.netty.channel.socket.DefaultDatagramChannelConfig#DefaultDatagramChannelConfig
public DefaultDatagramChannelConfig(DatagramChannel channel, DatagramSocket javaSocket) {
// 初始化 2048 字節(jié)的固定長度的接收緩沖區(qū)
super(channel, new FixedRecvByteBufAllocator(2048));
this.javaSocket = ObjectUtil.checkNotNull(javaSocket, "javaSocket");
}
原因
NioDatagramChannel 默認(rèn)緩沖區(qū)大小只給了 2048 ,開發(fā)一個 Syslog UDP 協(xié)議服務(wù),日志大小其實就不止這么點,所以日志被截取一部分導(dǎo)致問題出現(xiàn)
解決方法
構(gòu)建 Bootstrap 增加參數(shù)選項,把默認(rèn) 2048 固定緩沖區(qū)調(diào)大
實際構(gòu)建代碼如下:
def b = new Bootstrap()
group = new NioEventLoopGroup()
b.group(group)
.channel(NioDatagramChannel.class)
.localAddress(config.udp.port)
// 增加下面這一行代碼 固定 64 k大小,這個根據(jù)實際情況調(diào)整
.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(65535))
.handler(new ChannelInitializer<DatagramChannel>() {
@Override
protected void initChannel(DatagramChannel datagramChannel) throws Exception {
ChannelPipeline channelPipeline = datagramChannel.pipeline()
channelPipeline.addLast(
new UDPSyslogMessageDecoder(),
new SyslogMessageHandler()
)
if (config.log) {
channelPipeline.addLast(new SyslogMessageLogHandler())
}
channelPipeline.addLast(new QianxinLogHandler(vertx,config))
}
})
startFuture = b.bind().sync()