Netty的Channel.write写数据不能超过1024byte的问题解决

开发的时候总会遇到一些有趣的问题,Netty发送不了1024byte!已解决!

问题描述

这次主要使用netty建立WebSocket服务端,服务端可以正常收到消息,服务端调用writeAndFlush
客户端无法收到消息

调试

将io.netty日志等级降低到debug
日志打印 Encoding WebSocket Frame opCode=1 length=1074
length超过1024客户端就无法收到消息

服务端收到:{"random":"5926","code":1,"roomId":1}
2021-01-09 00:00:50.214 DEBUG 20316 --- [ntLoopGroup-3-1] i.n.h.c.h.w.WebSocket08FrameEncoder      : Encoding WebSocket Frame opCode=1 length=1074
检查依赖

发现io.netty版本不一致,可能会导致冲突!
在这里插入图片描述

解决

pom.xml添加以下代码片段

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>io.netty</groupId>
				<artifactId>netty-bom</artifactId>
				<version>4.1.36.Final</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
结果

在这里插入图片描述
搞定!关闭浏览器
在这里插入图片描述

代码片段1
@Component
@Slf4j
public class WebSocketNettyServer {

    private EventLoopGroup parentGroup = new NioEventLoopGroup();
    private EventLoopGroup childGroup = new NioEventLoopGroup();

    private Channel channel;

    public  ChannelFuture bing(InetSocketAddress address) {
        ChannelFuture channelFuture = null;

        try {

            ServerBootstrap b = new ServerBootstrap()
                    .group(parentGroup, childGroup)
                    .channel(NioServerSocketChannel.class)    //非阻塞模式
                    //子处理器,用于处理wss
                    .childHandler(new HttpChannelInitializer())
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    // 两小时没有数据通信时,TCP自动发送一个活动探测报文
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            channelFuture = b.bind(address).syncUninterruptibly();
            channel = channelFuture.channel();
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            if (null != channelFuture && channelFuture.isSuccess()) {
                log.info("dnetty server start done. ");
            } else {
                log.error("netty server start error. ");
            }
        }
        return channelFuture;
    }

    public  void destroy() {
        if (null == channel) return;
        channel.close();
        parentGroup.shutdownGracefully();
        childGroup.shutdownGracefully();
    }

    public Channel getChannel() {
        return channel;
    }

}
代码片段2
public class HttpChannelInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
		// HTTP 服务的解码器
        pipeline.addLast("http-codec", new HttpServerCodec());
        pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
        pipeline.addLast("http-chunked", new ChunkedWriteHandler());

        pipeline.addLast(new MyChannelHandler());
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的示例代码,实现了Springboot+protobuf+Netty传输文件的功能: 1. 定义protobuf消息格式 ```protobuf syntax = "proto3"; message FileRequest { string fileName = 1; } message FileResponse { int32 fileSize = 1; bytes fileContent = 2; } ``` 2. 编Netty服务端和客户端 Netty服务端: ```java @Component @ChannelHandler.Sharable public class FileServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FileRequest) { FileRequest request = (FileRequest) msg; String fileName = request.getFileName(); File file = new File(fileName); if (file.exists()) { byte[] fileContent = Files.readAllBytes(file.toPath()); FileResponse response = FileResponse.newBuilder() .setFileSize(fileContent.length) .setFileContent(ByteString.copyFrom(fileContent)) .build(); ctx.writeAndFlush(response); } else { // 文件不存在 ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } } else { super.channelRead(ctx, msg); } } } ``` Netty客户端: ```java @Component public class FileClient { private Bootstrap bootstrap; private EventLoopGroup group; private Channel channel; @PostConstruct public void init() { group = new NioEventLoopGroup(); bootstrap = new Bootstrap() .group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new ProtobufVarint32LengthFieldPrepender()); pipeline.addLast(new ProtobufEncoder()); pipeline.addLast(new ProtobufVarint32FrameDecoder()); pipeline.addLast(new ProtobufDecoder(FileResponse.getDefaultInstance())); pipeline.addLast(new FileClientHandler()); } }); } public void getFile(String fileName, String host, int port) throws InterruptedException { channel = bootstrap.connect(host, port).sync().channel(); FileRequest request = FileRequest.newBuilder() .setFileName(fileName) .build(); channel.writeAndFlush(request).sync(); } public void close() { channel.close(); group.shutdownGracefully(); } } @ChannelHandler.Sharable public class FileClientHandler extends SimpleChannelInboundHandler<FileResponse> { @Override protected void channelRead0(ChannelHandlerContext ctx, FileResponse msg) throws Exception { if (msg.getFileSize() > 0) { byte[] fileContent = msg.getFileContent().toByteArray(); // 将文件保存到本地 FileOutputStream fos = new FileOutputStream("local_file"); fos.write(fileContent); fos.close(); } else { // 文件不存在 System.err.println("File not found."); } } } ``` 3. 在Springboot中使用Netty 在Springboot中,可以使用@Configuration和@Bean注解来配置和启动Netty服务端和客户端: ```java @Configuration public class NettyConfig { @Autowired private FileServerHandler fileServerHandler; @Value("${netty.server.port}") private int serverPort; @Bean(name = "bossGroup") public EventLoopGroup bossGroup() { return new NioEventLoopGroup(); } @Bean(name = "workerGroup") public EventLoopGroup workerGroup() { return new NioEventLoopGroup(); } @Bean(name = "serverBootstrap") public ServerBootstrap serverBootstrap(@Qualifier("bossGroup") EventLoopGroup bossGroup, @Qualifier("workerGroup") EventLoopGroup workerGroup) { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new ProtobufVarint32FrameDecoder()); pipeline.addLast(new ProtobufDecoder(FileRequest.getDefaultInstance())); pipeline.addLast(fileServerHandler); } }); return bootstrap; } @Bean(initMethod = "bind", destroyMethod = "shutdownGracefully") public ChannelFuture serverChannelFuture(@Qualifier("serverBootstrap") ServerBootstrap serverBootstrap) { return serverBootstrap.bind(serverPort); } @Autowired private FileClient fileClient; @Value("${netty.client.host}") private String clientHost; @Value("${netty.client.port}") private int clientPort; @Bean(initMethod = "init", destroyMethod = "close") public FileClient fileClient() { return new FileClient(); } } ``` 4. 实现文件传输功能 在Springboot中,可以使用@RestController注解定义一个HTTP接口,用于调用Netty客户端获取文件: ```java @RestController public class FileController { @Autowired private FileClient fileClient; @GetMapping("/file/{fileName}") public String getFile(@PathVariable String fileName) { try { fileClient.getFile(fileName, "localhost", 8000); return "File downloaded successfully."; } catch (InterruptedException e) { e.printStackTrace(); return "File download failed."; } } } ``` 这样,当调用http://localhost:8080/file/test.txt时,就可以从Netty服务端下载test.txt文件并保存到本地。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值