Netty UDP 接收缓冲区 报文截取问题

Netty UDP 报文截取问题

问题

  • 最近在写一个 syslog udp 日志接收器,然后发现接收过大的日志数据会被截断,拿到的信息不完整

源码追踪

创建 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));
    }
  • 调用构造方法
    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;
    }
  • 调用父类构造方法
    io.netty.channel.socket.DefaultDatagramChannelConfig#DefaultDatagramChannelConfig
    public DefaultDatagramChannelConfig(DatagramChannel channel, DatagramSocket javaSocket) {
        // 初始化 2048 字节的固定长度的接收缓冲区
        super(channel, new FixedRecvByteBufAllocator(2048));
        this.javaSocket = ObjectUtil.checkNotNull(javaSocket, "javaSocket");
    }

原因

NioDatagramChannel 默认缓冲区大小只给了 2048 ,开发一个 Syslog UDP 协议服务,日志大小其实就不止这么点,所以日志被截取一部分导致问题出现

解决方法

构建 Bootstrap 增加参数选项,把默认 2048 固定缓冲区调大

实际构建代码如下:

       def b = new Bootstrap()
        group = new NioEventLoopGroup()
        b.group(group)
                .channel(NioDatagramChannel.class)
                .localAddress(config.udp.port)
                // 增加下面这一行代码 固定 64 k大小,这个根据实际情况调整
                .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()
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty是一个高性能、异步事件驱动的网络应用程序框架,它支持多种传输协议,包括TCP、UDP、HTTP、WebSocket等。 下面是一个简单的Netty UDP客户端的示例代码: ```java public class UdpClient { public static void main(String[] args) throws Exception { // 创建 Bootstrap 对象 Bootstrap bootstrap = new Bootstrap(); // 设置 EventLoopGroup 对象 EventLoopGroup group = new NioEventLoopGroup(); try { // 配置 Bootstrap 对象 bootstrap.group(group) .channel(NioDatagramChannel.class) .option(ChannelOption.SO_BROADCAST, true) .handler(new UdpClientHandler()); // 绑定端口并启动客户端 Channel channel = bootstrap.bind(0).sync().channel(); // 发送数据 channel.writeAndFlush(new DatagramPacket( Unpooled.copiedBuffer("Hello, Netty UDP", CharsetUtil.UTF_8), new InetSocketAddress("255.255.255.255", 8080))).sync(); // 等待关闭 channel.closeFuture().await(); } finally { // 关闭 EventLoopGroup 对象 group.shutdownGracefully(); } } } class UdpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> { @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { // 接收到响应数据 ByteBuf buf = msg.content(); System.out.println(buf.toString(CharsetUtil.UTF_8)); } } ``` 此示例中,我们创建了一个Bootstrap对象,设置了NioEventLoopGroup和UDP通道,然后绑定端口并发送数据。我们还定义了一个UdpClientHandler类来处理接收到的响应数据。 在发送数据时,我们使用DatagramPacket对象指定要发送的数据和目标地址。在接收响应数据时,我们使用SimpleChannelInboundHandler类的channelRead0()方法来处理接收到的数据。 这只是一个简单的示例,你可以根据需要自定义Netty UDP客户端的行为。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值