Netty入门P11

数据在InboundHandler链上的传递

Server示例代码:

/**
 * @program: learnnetty
 * @description: 事件传播
 * @create: 2020-05-08 16:40
 **/
public class Server {
    public static void main(String[] args) {
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap
                .group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel
                                .pipeline()
                                .addLast(new InboundHandlerA())
                                .addLast(new InboundHandlerB())
                                .addLast(new InboundHandlerC());
                    }
                });

        bootstrap.bind("127.0.0.1", 8080);
    }
}

处理器A示例代码:

/**
 * @program: learnnetty
 * @description: 处理器A
 * @create: 2020-05-08 16:41
 **/
public class InboundHandlerA extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf)msg;
        System.out.println("InboundHandlerA:" + byteBuf.toString(StandardCharsets.UTF_8));
        byteBuf.writeBytes(",A add".getBytes());
        ctx.fireChannelRead(byteBuf);
    }
}

处理器B示例代码:

/**
 * @program: learnnetty
 * @description: 处理器B
 * @create: 2020-05-08 16:42
 **/
public class InboundHandlerB extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf)msg;
        System.out.println("InboundHandlerB:" + byteBuf.toString(StandardCharsets.UTF_8));
        byteBuf.writeBytes(",B add".getBytes());
        ctx.fireChannelRead(byteBuf);
    }
}

处理器C示例代码:

/**
 * @program: learnnetty
 * @description: 处理器C
 * @create: 2020-05-08 16:42
 **/
public class InboundHandlerC extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf)msg;
        System.out.println("InboundHandlerC:" + byteBuf.toString(StandardCharsets.UTF_8));
        byteBuf.writeBytes(",C add".getBytes());
        ctx.fireChannelRead(byteBuf);
    }
}

输出:

InboundHandlerA:123
InboundHandlerB:123,A add
InboundHandlerC:123,A add,B add

如果有需要在处理链上传播,则可以使用ChannelHandlerContext.fireChannelRead()将当前以完成处理的数据交由下一个处理器处理。

数据在OutboundHandler链上的传递

修改后的Server示例代码:

/**
 * @program: learnnetty
 * @description: 事件传播
 * @create: 2020-05-08 16:40
 **/
public class Server {
    public static void main(String[] args) {
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap
                .group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel
                                .pipeline()
                                .addLast(new InboundHandlerA())
                                .addLast(new OutboundHandlerA())
                                .addLast(new OutboundHandlerB())
                                .addLast(new OutboundHandlerC());
                    }
                });

        bootstrap.bind("127.0.0.1", 8080);
    }
}

做出反馈的InboundHandlerA示例代码:

/**
 * @program: learnnetty
 * @description: 处理器A
 * @create: 2020-05-08 16:41
 **/
public class InboundHandlerA extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("收到:" + msg);
        ctx.channel().writeAndFlush(Unpooled.wrappedBuffer("321".getBytes()));
    }
}

OutboundHandlerA示例代码:

/**
 * @program: learnnetty
 * @description: 处理器A
 * @create: 2020-05-08 16:54
 **/
public class OutboundHandlerA extends ChannelOutboundHandlerAdapter {
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("OutA");
        ByteBuf byteBuf = (ByteBuf)msg;
        //需要发送的信息
        String msgStr = ",A add";
        //旧的ByteBuf可写入字符数为0,新建一个
        ByteBuf buf = ctx.alloc().ioBuffer(byteBuf.readableBytes() + msgStr.getBytes().length);
        //旧数据
        byte[] oldData = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(oldData);
        //新旧数据写入新的ByteBuf
        buf.writeBytes(oldData);
        buf.writeBytes(msgStr.getBytes());
        System.out.println("A updated msg");
        //释放旧的ByteBuf
        byteBuf.release();
        //传递
        ctx.write(buf, promise);
    }
}

OutboundHandlerB示例代码:

/**
 * @program: learnnetty
 * @description: 处理器B
 * @create: 2020-05-08 16:55
 **/
public class OutboundHandlerB extends ChannelOutboundHandlerAdapter {
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("OutB");
        ByteBuf byteBuf = (ByteBuf)msg;
        //需要发送的信息
        String msgStr = ",B add";
        //旧的ByteBuf可写入字符数为0,新建一个
        ByteBuf buf = ctx.alloc().ioBuffer(byteBuf.readableBytes() + msgStr.getBytes().length);
        //旧数据
        byte[] oldData = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(oldData);
        //新旧数据写入新的ByteBuf
        buf.writeBytes(oldData);
        buf.writeBytes(msgStr.getBytes());
        System.out.println("B updated msg");
        //释放旧的ByteBuf
        byteBuf.release();
        //传递
        ctx.write(buf, promise);
    }
}

OutboundHandlerC示例代码:

/**
 * @program: learnnetty
 * @description: 处理器C
 * @create: 2020-05-08 16:55
 **/
public class OutboundHandlerC extends ChannelOutboundHandlerAdapter {
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("OutC");
        ByteBuf byteBuf = (ByteBuf)msg;
        //需要发送的信息
        String msgStr = ",C add";
        //旧的ByteBuf可写入字符数为0,新建一个
        ByteBuf buf = ctx.alloc().ioBuffer(byteBuf.readableBytes() + msgStr.getBytes().length);
        //旧数据
        byte[] oldData = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(oldData);
        //新旧数据写入新的ByteBuf
        buf.writeBytes(oldData);
        buf.writeBytes(msgStr.getBytes());
        System.out.println("C updated msg");
        //释放旧的ByteBuf
        byteBuf.release();
        //传递
        ctx.write(buf, promise);
    }
}

输出:

收到:PooledUnsafeDirectByteBuf(ridx: 0, widx: 3, cap: 1024)
OutC
C updated msg
OutB
B updated msg
OutA
A updated msg

Netty入门P11_第1张图片
因为传入的ByteBuf可写入字节数为0,因此要添加新的数据需要新建一个ByteBuf,用新建的ByteBuf替换掉旧的ByteBuf用于存储添加的数据。

本人新手一枚,在学习InboundHandler传递链时突发奇想,在OutboundHandler传递数据时是不是也能这么做,所以才有了以上代码,尚不清楚这样代码有何影响。

ByteToMessageDecoder

用于解析二进制数据包的FrameDecoder.java

/**
 * @program: learnnetty
 * @description: 解码
 * @create: 2020-05-08 20:14
 **/
public class FrameDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        list.add(ParseFrame.getInstance().decode(byteBuf));
    }
}

值的注意的是如果使用ByteToMessageDecoder进行解码的话,在此处使用的ByteBuf会被自动释放,而非手动释放。

使用XXXXHandler拆解if-else

修改后的客户端Client:

/**
 * @program: learnnetty
 * @description: 客户端
 * @create: 2020-05-06 15:39
 **/
public class Client {
    private static final int MAX_RETRY = 5;

    public static void main(String[] args) {
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap
                .group(workerGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel
                                .pipeline()
                                .addLast(new FrameDecoder())
                                .addLast(new ClientLoginHandler())
                                .addLast(new ClientMsgHandler());
                    }
                });

       connect(bootstrap, "127.0.0.1", 8080, MAX_RETRY);
    }

    private static void connect(final Bootstrap bootstrap, final String host, final int port, final int retry){
        bootstrap.connect(host, port).addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (future.isSuccess()){
                    System.out.println("客户端连接成功");
                    Channel channel = ((ChannelFuture)future).channel();
                    startConsoleThread(channel);
                }else if (retry == 0){
                    System.out.println("客户端连接失败次数过多,放弃连接");
                }else {
                    System.out.println("客户端连接失败,尝试重连");
                    int order = MAX_RETRY - retry + 1;
                    int delay = 1 << order;
                    System.out.println(new Date() + " 连接失败,第" + order + "次连接");
                    bootstrap.config().group().schedule(new Runnable() {
                        @Override
                        public void run() {
                            connect(bootstrap, host, port, retry - 1);
                        }
                    }, delay, TimeUnit.SECONDS);
                }
            }
        });
    }

    private static void startConsoleThread(final Channel channel){
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.interrupted()){
                    if (LoginUtil.hasLogin(channel)){
                        System.out.println("输入消息发送至服务端:");
                        Scanner scanner = new Scanner(System.in);
                        String line = scanner.nextLine();

                        MsgRequestFrame requestFrame = new MsgRequestFrame();
                        requestFrame.setContent(line);
                        ByteBuf byteBuf = ParseFrame.getInstance().encode(channel.alloc(), requestFrame);
                        channel.writeAndFlush(byteBuf);
                    }
                }
            }
        }).start();
    }
}

拆解后的ClientLoginHandler:

/**
 * @program: learnnetty
 * @description: 服务端处理信息
 * @create: 2020-05-08 20:36
 **/
public class ClientLoginHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(new Date() + ",客户端开始登录");

        LoginRequestFrame loginFrame = new LoginRequestFrame();
        loginFrame.setUserId(UUID.randomUUID().toString());
        loginFrame.setUserName("zcd");
        loginFrame.setPassword("zzz");

        ByteBuf buf = ParseFrame.getInstance().encode(ctx.alloc(), loginFrame);

        ctx.channel().writeAndFlush(buf);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        BaseFrame frame = (BaseFrame) msg;

        if (frame instanceof LoginResponseFrame){
            LoginResponseFrame responseFrame = (LoginResponseFrame) frame;

            if (responseFrame.isSuccess()){
                LoginUtil.markAsLogin(ctx.channel());
                System.out.println("客户端登录成功");
            }else {
                System.out.println("客户端登录失败,原因:" + responseFrame.getMsg());
            }
        }else {
            ctx.fireChannelRead(frame);
        }
    }
}

拆解后的ClientMsgHandler:

/**
 * @program: learnnetty
 * @description: 信息响应Handler
 * @create: 2020-05-08 20:26
 **/
public class ClientMsgHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        BaseFrame frame = (BaseFrame) msg;
        if (frame instanceof MsgResponseFrame){
            MsgResponseFrame responseFrame = (MsgResponseFrame) frame;
            System.out.println(new Date() + ",收到来自服务器的消息:" + responseFrame.getContent());
        }else {
            ctx.fireChannelRead(frame);
        }

    }
}

修改后的服务端Server:

/**
 * @program: learnnetty
 * @description: 服务端
 * @create: 2020-05-06 17:18
 **/
public class Server {

    public static void main(String[] args) {
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap
                .group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel
                                .pipeline()
                                .addLast(new FrameDecoder())
                                .addLast(new ServerLoginHandler())
                                .addLast(new ServerMsgHandler());
                    }
                });

        bind(serverBootstrap, 8080);
    }

    private static void bind(final ServerBootstrap serverBootstrap, final int port){
        serverBootstrap.bind(port).addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (future.isSuccess()){
                    System.out.println("端口[" + port + "]绑定成功");
                }else {
                    System.out.println("端口[" + port + "]绑定失败,尝试绑定[" + (port + 1) + "]端口");
                    bind(serverBootstrap, port + 1);
                }
            }
        });
    }
}

拆解后的ServerLoginHandler:

/**
 * @program: learnnetty
 * @description: 服务端处理
 * @create: 2020-05-06 17:19
 **/
public class ServerLoginHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println(new Date() + ",服务端开始处理请求");
        BaseFrame baseFrame = (BaseFrame)msg;

        if (baseFrame instanceof LoginRequestFrame){
            LoginRequestFrame requestFrame = (LoginRequestFrame)baseFrame;
            LoginResponseFrame responseFrame = new LoginResponseFrame();
            responseFrame.setUserId(requestFrame.getUserId());
            responseFrame.setUserName(requestFrame.getUserName());

            if(requestFrame.getUserName().equals("zcd") && requestFrame.getPassword().equals("zzz")){
                responseFrame.setSuccess(true);
                responseFrame.setMsg("登录成功");
                System.out.println(new Date() + ",zcd客户端登录成功");
            }else {
                responseFrame.setSuccess(false);
                responseFrame.setMsg("密码或用户名错误");
                System.out.println(new Date() + ",zcd客户端登录失败");
            }

            ByteBuf respByteBuf = ParseFrame.getInstance().encode(ctx.alloc(), responseFrame);
            ctx.channel().writeAndFlush(respByteBuf);
        }else {
            ctx.fireChannelRead(baseFrame);
        }
    }
}

拆解后的ServerMsgHandler:

/**
 * @program: learnnetty
 * @description: 服务端处理信息
 * @create: 2020-05-08 20:36
 **/
public class ServerMsgHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        BaseFrame baseFrame = (BaseFrame) msg;
        if (baseFrame instanceof MsgRequestFrame){
            MsgRequestFrame msgRequestFrame = (MsgRequestFrame)baseFrame;
            System.out.println(new Date() + ",收到来自客户端的消息:" + msgRequestFrame.getContent());

            MsgResponseFrame responseFrame = new MsgResponseFrame();
            responseFrame.setContent("服务器已收到消息");
            ByteBuf respByteBuf = ParseFrame.getInstance().encode(ctx.alloc(), responseFrame);
            ctx.channel().writeAndFlush(respByteBuf);
        }else {
            ctx.fireChannelRead(baseFrame);
        }
    }
}

客户端输出:

客户端连接成功
Fri May 08 20:41:16 CST 2020,客户端开始登录
客户端登录成功
输入消息发送至服务端:
123
输入消息发送至服务端:
Fri May 08 20:41:19 CST 2020,收到来自服务器的消息:服务器已收到消息

服务端输出:

端口[8080]绑定成功
Fri May 08 20:41:16 CST 2020,服务端开始处理请求
Fri May 08 20:41:16 CST 2020,zcd客户端登录成功
Fri May 08 20:41:19 CST 2020,服务端开始处理请求
Fri May 08 20:41:19 CST 2020,收到来自客户端的消息:123

值的注意的是客户端和服务端在FrameDecoder之后传递的都是BaseFrame而非ByteBuf。

MessageToByteEncoder

抽取方法并使用编码类之后的Client示例代码:

/**
 * @program: learnnetty
 * @description: 客户端
 * @create: 2020-05-06 15:39
 **/
public class Client {
    private static final int MAX_RETRY = 5;

    public static void main(String[] args) {
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap
                .group(workerGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel
                                .pipeline()
                                .addLast(new FrameDecoder())
                                .addLast(new ClientLoginHandler())
                                .addLast(new ClientMsgHandler())
                                .addLast(new FrameEncoder());
                    }
                });

       connect(bootstrap, "127.0.0.1", 8080, MAX_RETRY);
    }

    private static void connect(final Bootstrap bootstrap, final String host, final int port, final int retry){
        bootstrap.connect(host, port).addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (future.isSuccess()){
                    System.out.println("客户端连接成功");
                    Channel channel = ((ChannelFuture)future).channel();
                    startConsoleThread(channel);
                }else if (retry == 0){
                    System.out.println("客户端连接失败次数过多,放弃连接");
                }else {
                    System.out.println("客户端连接失败,尝试重连");
                    int order = MAX_RETRY - retry + 1;
                    int delay = 1 << order;
                    System.out.println(new Date() + " 连接失败,第" + order + "次连接");
                    bootstrap.config().group().schedule(new Runnable() {
                        @Override
                        public void run() {
                            connect(bootstrap, host, port, retry - 1);
                        }
                    }, delay, TimeUnit.SECONDS);
                }
            }
        });
    }

    private static void startConsoleThread(final Channel channel){
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.interrupted()){
                    if (LoginUtil.hasLogin(channel)){
                        System.out.println("输入消息发送至服务端:");
                        Scanner scanner = new Scanner(System.in);
                        String line = scanner.nextLine();
                        channel.writeAndFlush(MsgUtil.reqMsg(line));
                    }
                }
            }
        }).start();
    }
}

使用编码器之后的Server示例代码:

/**
 * @program: learnnetty
 * @description: 服务端
 * @create: 2020-05-06 17:18
 **/
public class Server {

    public static void main(String[] args) {
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap
                .group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel
                                .pipeline()
                                .addLast(new FrameDecoder())
                                .addLast(new ServerLoginHandler())
                                .addLast(new ServerMsgHandler())
                                .addLast(new FrameEncoder());
                    }
                });

        bind(serverBootstrap, 8080);
    }

    private static void bind(final ServerBootstrap serverBootstrap, final int port){
        serverBootstrap.bind(port).addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (future.isSuccess()){
                    System.out.println("端口[" + port + "]绑定成功");
                }else {
                    System.out.println("端口[" + port + "]绑定失败,尝试绑定[" + (port + 1) + "]端口");
                    bind(serverBootstrap, port + 1);
                }
            }
        });
    }
}

新建的编码器类FrameEncoder示例代码:

/**
 * @program: learnnetty
 * @description: 编码
 * @create: 2020-05-09 10:57
 **/
public class FrameEncoder extends MessageToByteEncoder<BaseFrame> {
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, BaseFrame baseFrame, ByteBuf byteBuf) throws Exception {
        ParseFrame.getInstance().encode(byteBuf, baseFrame);
    }
}

抽取方法之后的ClientLoginHandler处理器类示例代码:

/**
 * @program: learnnetty
 * @description: 客户端业务处理
 * @create: 2020-05-06 15:40
 **/
public class ClientLoginHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(new Date() + ",客户端开始登录");

        LoginRequestFrame loginFrame = new LoginRequestFrame();
        loginFrame.setUserId(UUID.randomUUID().toString());
        loginFrame.setUserName("zcd");
        loginFrame.setPassword("zzz");

        ctx.channel().writeAndFlush(loginFrame);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        BaseFrame frame = (BaseFrame) msg;

        if (frame instanceof LoginResponseFrame){
            LoginUtil.resolveRespLoginFrame(frame, ctx);
        }else {
            ctx.fireChannelRead(frame);
        }
    }
}

抽取方法之后的ClientMsgHandler处理器类示例代码:

/**
 * @program: learnnetty
 * @description: 信息响应Handler
 * @create: 2020-05-08 20:26
 **/
public class ClientMsgHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        BaseFrame frame = (BaseFrame) msg;
        if (frame instanceof MsgResponseFrame){
            MsgUtil.resolveRespMsg(frame);
        }else {
            ctx.fireChannelRead(frame);
        }

    }
}

抽取方法之后的ServerLoginHandler处理器类:

/**
 * @program: learnnetty
 * @description: 服务端处理
 * @create: 2020-05-06 17:19
 **/
public class ServerLoginHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println(new Date() + ",服务端开始处理请求");
        BaseFrame baseFrame = (BaseFrame)msg;

        if (baseFrame instanceof LoginRequestFrame){
            ctx.channel().writeAndFlush(LoginUtil.respLogin(baseFrame));
        }else {
            ctx.fireChannelRead(baseFrame);
        }
    }
}

抽取方法之后的ServerMsgHandler处理器类示例代码:

/**
 * @program: learnnetty
 * @description: 服务端处理信息
 * @create: 2020-05-08 20:36
 **/
public class ServerMsgHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        BaseFrame baseFrame = (BaseFrame) msg;
        if (baseFrame instanceof MsgRequestFrame){
            ctx.channel().writeAndFlush(MsgUtil.respMsg(baseFrame));
        }else {
            ctx.fireChannelRead(baseFrame);
        }
    }
}

登录相关工具类LoginUtil示例代码:

/**
 * @program: learnnetty
 * @description: 登录工具类
 * @create: 2020-05-07 16:38
 **/
public class LoginUtil {

    /**
     * 标记登录
     */
    public static void markAsLogin(Channel channel){
        channel.attr(Attributes.LOGIN).set(true);
    }

    /**
     * 检查是否登录
     */
    public static boolean hasLogin(Channel channel){
        Attribute<Boolean> loginAttr = channel.attr(Attributes.LOGIN);
        if (loginAttr.get() == null){
            return false;
        }
        return loginAttr.get();
    }

    /**
     * 生成响应登录数据包
     */
    public static BaseFrame respLogin(BaseFrame baseFrame){
        LoginRequestFrame requestFrame = (LoginRequestFrame)baseFrame;
        LoginResponseFrame responseFrame = new LoginResponseFrame();
        responseFrame.setUserId(requestFrame.getUserId());
        responseFrame.setUserName(requestFrame.getUserName());

        if(requestFrame.getUserName().equals("zcd") && requestFrame.getPassword().equals("zzz")){
            responseFrame.setSuccess(true);
            responseFrame.setMsg("登录成功");
            System.out.println(new Date() + ",zcd客户端登录成功");
        }else {
            responseFrame.setSuccess(false);
            responseFrame.setMsg("密码或用户名错误");
            System.out.println(new Date() + ",zcd客户端登录失败");
        }

        return responseFrame;
    }

    /**
     * 处理登录响应数据包
     */
    public static void resolveRespLoginFrame(BaseFrame frame, ChannelHandlerContext ctx){
        LoginResponseFrame responseFrame = (LoginResponseFrame) frame;

        if (responseFrame.isSuccess()){
            LoginUtil.markAsLogin(ctx.channel());
            System.out.println("客户端登录成功");
        }else {
            System.out.println("客户端登录失败,原因:" + responseFrame.getMsg());
        }
    }
}

信息相关工具类MsgUtil示例代码:

/**
 * @program: learnnetty
 * @description: Msg相关处理
 * @create: 2020-05-09 11:17
 **/
public class MsgUtil {

    /**
     * 对Msg做出响应
     */
    public static BaseFrame respMsg(BaseFrame baseFrame) {
        MsgRequestFrame msgRequestFrame = (MsgRequestFrame)baseFrame;
        System.out.println(new Date() + ",收到来自客户端的消息:" + msgRequestFrame.getContent());

        MsgResponseFrame responseFrame = new MsgResponseFrame();
        responseFrame.setContent("服务器已收到消息");
        return responseFrame;
    }

    /**
     * 处理反馈的Msg
     */
    public static void resolveRespMsg(BaseFrame baseFrame){
        MsgResponseFrame responseFrame = (MsgResponseFrame) baseFrame;
        System.out.println(new Date() + ",收到来自服务器的消息:" + responseFrame.getContent());
    }

    /**
     * 发送请求Msg
     */
    public static BaseFrame reqMsg(String line){
        MsgRequestFrame requestFrame = new MsgRequestFrame();
        requestFrame.setContent(line);
        return requestFrame;
    }

}

客户端输出:

客户端连接成功
Sat May 09 11:22:20 CST 2020,客户端开始登录
客户端登录成功
输入消息发送至服务端:
123
输入消息发送至服务端:
Sat May 09 11:22:22 CST 2020,收到来自服务器的消息:服务器已收到消息

服务端输出:

端口[8080]绑定成功
Sat May 09 11:22:20 CST 2020,服务端开始处理请求
Sat May 09 11:22:20 CST 2020,zcd客户端登录成功
Sat May 09 11:22:22 CST 2020,服务端开始处理请求
Sat May 09 11:22:22 CST 2020,收到来自客户端的消息:123

你可能感兴趣的:(学习笔记,netty)