Netty實戰練習——tcp拆包和粘包

一、發現問題

繼續上篇帖子的內容,https://blog.csdn.net/weixin_43599368/article/details/84206351

利用java原生序列化方式來編碼解碼,其餘代碼如下:

RpcClient:

package rpcserver.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import rpcserver.common.InputParam;
import rpcserver.common.OriginJava.ClientMessageDecoder;
import rpcserver.common.OriginJava.ClientMessageEncoder;


public class RpcClient {
    int port;
    String host;

    public RpcClient(int port, String host) {
        this.port = port;
        this.host = host;
    }

    public void run() {
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()
//                                    第一種java原生的序列化方式
                                    .addLast("decoder", new ClientMessageDecoder())
                                    .addLast("encoder", new ClientMessageEncoder())
                                    .addLast(new RpcClientHandler());

                        }
                    });

            Channel channel = bootstrap.connect(host, port).sync().channel();
            for(int i = 0; i < 100; i ++) {
                InputParam inputParam = new InputParam();
                inputParam.setNum1(i);
                inputParam.setNum2(i * 2);
                channel.writeAndFlush(inputParam);
                System.out.println("client 發送出去的信息是" + inputParam.toString());
            }

            //從鍵盤讀出一個字符,然後返回它的Unicode碼;目的是等待client接收完消息再退出
            System.in.read();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new RpcClient(8080, "127.0.0.1").run();
    }
}

RpcClientHandler:

public class RpcClientHandler extends SimpleChannelInboundHandler {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object outputParam) throws Exception {
        System.out.println("client接受到的數據是:" + outputParam.toString());
    }
}

RpcServer:

package rpcserver.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import rpcserver.common.OriginJava.ServerMessageDecoder;
import rpcserver.common.OriginJava.ServerMessageEncoder;

public class RpcServer {
    private int port;

    public RpcServer(int port) {
        this.port = port;
    }

    public void run() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()
//                                    第一種java原生的序列化方式
                                    .addLast("decoder", new ServerMessageDecoder())
                                    .addLast("encoder", new ServerMessageEncoder())
                                    .addLast(new RpcServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = serverBootstrap.bind(port).sync();
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            System.out.println("RpcServer error:" + e);
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            System.out.println("RpcServer 關閉了");
        }

    }

    public static void main(String[] args) {
        int port;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        } else {
            port = 8080;
        }
        new RpcServer(port).run();
    }

}

RpcServerHandler:

public class RpcServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        InputParam inputParam = (InputParam) msg;
        System.out.println("server 接受到的數據是 " + inputParam.toString());

        OutputParam outputParam = new OutputParam();
        outputParam.setStr1("第一個數是:"+String.valueOf(inputParam.getNum1()));
        outputParam.setStr2("第二個數是:"+String.valueOf(inputParam.getNum2()));
        ctx.writeAndFlush(outputParam);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

}

運行

client連續發送2條數據,運行結果如下:

而client發送100條數據,卻出現問題:

server端接收到13條就報錯,懷疑發生了tcp粘包與拆包。

二、

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章