AI工具人
提示词工程师

在netty中使用protobuf并实现数据加密传输

  最近学习netty,为了实践一些知识点,写了一个小demo,完成了client和server端之间的加密数据传输,并使用了protobuf对数据进行封装,代码虽然简单,但对初学者学习netty应该会有些许帮助,特此记录分享。
  首先来看Server的实现,Server和所有的netty示例代码差不多,都是构建netty的ServerBootstrap。

package xyz.xindoo.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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 io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;

public class Server {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
         .channel(NioServerSocketChannel.class)
         .option(ChannelOption.SO_BACKLOG, 100)
         .childHandler(new ChannelInitializer<SocketChannel>() {
             @Override
             public void initChannel(SocketChannel ch) throws Exception {
                 ChannelPipeline p = ch.pipeline();
                 p.addLast(new LengthFieldBasedFrameDecoder(10240, 0, 2, 0, 2));
                 p.addLast(new LengthFieldPrepender(2));
                 p.addLast(new DecryptHandler());
                 p.addLast(new EncryptHandler());
                 p.addLast(new MessageDecoder());
                 p.addLast(new MessageEncoder());
                 p.addLast(new ServerHandler());
             }
         });
        try {
            ChannelFuture f = b.bind(9999).sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  在这个示例中,我其实是实现了3层编解码,第一层的LengthFieldXXX对应的是netty中的变成编码,第二层的DecryptHandler和EncryptHandler实现了数据的加解密,第三次的MessageDecode和MessageEncode是对数据进行protobuf序列化和反序列化。而最后的ServerHandler实现了对数据的处理,实际这里没啥逻辑,就是返回了消息体的原始长度。整体消息出入处理流程如下:
在这里插入图片描述
  接下来我们看下Client的具体实现。

package xyz.xindoo.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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 io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;

/**
 * @author zhangweibin005
 * @date 2022/7/12
 */
public class Client {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(bossGroup)
                 .channel(NioSocketChannel.class)
                 .option(ChannelOption.SO_BACKLOG, 100)
                 .handler(new ChannelInitializer<SocketChannel>() {
                     @Override
                     public void initChannel(SocketChannel ch) throws Exception {
                         ChannelPipeline p = ch.pipeline();
                         p.addLast(new LengthFieldBasedFrameDecoder(10240, 0, 2, 0, 2));
                         p.addLast(new LengthFieldPrepender(2));
                         p.addLast(new DecryptHandler());
                         p.addLast(new EncryptHandler());
                         p.addLast(new MessageDecoder());
                         p.addLast(new MessageEncoder());
                         p.addLast(new ClientHandler());
                     }
                 });
        try {
            Channel c = bootstrap.connect("127.0.0.1", 9999).sync().channel();
            ClientHandler clientHandler = c.pipeline().get(ClientHandler.class);
            clientHandler.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

  Client和Server乍眼一看几乎一模一样,仔细看其实是有些小细节不同,和Server不同的是Clint使用了Bootstrap而不是ServerBootstrap。另外这里需要特别提醒下,很多时候我们在写Server或者Client时所有的编解码都是成对出现的,而且通常使用同一种,会导致一种误区,Server端或者Client Encoder和Decoder必须成对出现。比如用了StringEncoder就必须用StringDecoder。 实际上这不完全对,成对出现是指Server和Client端需要使用对应的Decoder和Encoder,也就是出单其中某一端,其实可以使用不同的Decoder和Encoder。
  接下来我们看下其他几个的代码,因为LengthFieldBasedFrameDecoder和LengthFieldPrepender是netty提供的,所以这里不再展示。我们先来看下加解密部分DecryptHandler和EncryptHandler。

赞(0) 打赏
未经允许不得转载:XINDOO » 在netty中使用protobuf并实现数据加密传输
描述文字

评论 抢沙发

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫