Netty应用(二)传输Protobuf数据类型

29 篇文章 1 订阅
10 篇文章 0 订阅

接上面两篇文章:

Netty应用(一)基本模型 https://blog.csdn.net/xxkalychen/article/details/115876196

Protobuf初次使用小记 https://blog.csdn.net/xxkalychen/article/details/115875643?spm=1001.2014.3001.5501

一、服务器端

1. gradle依赖

    compile 'io.netty:netty-all:4.1.63.Final'
    implementation 'com.google.protobuf:protobuf-java:3.15.8'
    implementation 'com.google.protobuf:protobuf-java-util:3.15.8'

2. 创建.proto文件,实际上是从上一个例子中复制过来的。需要修改,只修改包名,所有的message都必须和客户端的文件保持一致。

syntax = "proto2";

package com.chris.netty.server.proto;

option java_outer_classname = "ProtobufData";

message Person {
    required string name = 1;
    required int32 age = 2;
    required Gender gender = 3;
    required string address = 4;
    required Job job = 5;

    enum Gender {
        MAN = 1;
        WOMEN = 2;
    }

    message Job {
        required string companyName = 1;
        required string work = 2;
    }
}

3. 生成Java类,在工程根部执行

protoc --java_out=./src/main/java/ ./src/proto/Person.proto

4. 自定义处理器

package com.chris.netty.server.handler;

import com.chris.netty.server.proto.ProtobufData;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * @author Chris Chan
 * Create on 2021/4/19 21:17
 * Use for:
 * Explain:
 */
public class ProtobufServerHandler extends SimpleChannelInboundHandler<ProtobufData.Person> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ProtobufData.Person msg) throws Exception {
        System.out.println(msg.getName() + " : " + msg.getJob().getWork());
    }
}

5. 自定义初始化器

package com.chris.netty.server.handler;

import com.chris.netty.server.proto.ProtobufData;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

/**
 * @author Chris Chan
 * Create on 2021/4/19 21:16
 * Use for:
 * Explain:
 */
public class ProtobufServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline()
                .addLast("ProtobufEncoder", new ProtobufEncoder())
                .addLast("ProtobufDecoder", new ProtobufDecoder(ProtobufData.Person.getDefaultInstance()))
                .addLast("ProtobufVarint32FrameDecoder", new ProtobufVarint32FrameDecoder())
                .addLast("ProtobufVarint32LengthFieldPrepender", new ProtobufVarint32LengthFieldPrepender())
                .addLast("ProtobufServerHandler", new ProtobufServerHandler());
    }
}

6. 测试文件

package com.chris.netty.server;

import com.chris.netty.server.handler.ProtobufServerInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * @author Chris Chan
 * Create on 2021/4/19 21:05
 * Use for:
 * Explain:
 */
public class ProtobufServer {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ProtobufServerInitializer());
            serverBootstrap
                    .bind(8001)
                    .sync()
                    .channel()
                    .closeFuture()
                    .sync();
        } catch (Exception e) {

        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}

二、客户端

1. 依赖和工程结构都是一样的,.proto文件直接复制过来,不能修改message,可以修改包名。

2. 自定义处理器

package com.chris.netty.client.handler;

import com.chris.netty.client.proto.ProtobufData;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * @author Chris Chan
 * Create on 2021/4/19 21:34
 * Use for:
 * Explain:
 */
public class ProtobufClientHandler extends SimpleChannelInboundHandler<ProtobufData.Person> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ProtobufData.Person msg) throws Exception {
        System.out.println(msg.getName());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //构建对象
        ProtobufData.Person person = ProtobufData
                .Person
                .newBuilder()
                .setName("chris")
                .setAge(44)
                .setGender(ProtobufData.Person.Gender.MAN)
                .setAddress("中国上海")
                .setJob(ProtobufData.Person.Job.newBuilder().setCompanyName("满天星公司").setWork("Java开发"))
                .build();
        ctx.writeAndFlush(person);
    }
}

当channel处于激活状态时,构建对象然后传输。

3.自定义初始化器

package com.chris.netty.client.handler;

import com.chris.netty.client.proto.ProtobufData;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

/**
 * @author Chris Chan
 * Create on 2021/4/19 21:31
 * Use for:
 * Explain:
 */
public class ProtobufClientInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline()
                .addLast("ProtobufEncoder", new ProtobufEncoder())
                .addLast("ProtobufDecoder", new ProtobufDecoder(ProtobufData.Person.getDefaultInstance()))
                .addLast("ProtobufVarint32FrameDecoder", new ProtobufVarint32FrameDecoder())
                .addLast("ProtobufVarint32LengthFieldPrepender", new ProtobufVarint32LengthFieldPrepender())
                .addLast("ProtobufServerHandler", new ProtobufClientHandler());
    }
}

基本使用方式大同小异,处理器都是匹配Protobuf协议的。解码器需要我们传输数据的泛型。

4. 测试类

package com.chris.netty.client;

import com.chris.netty.client.handler.ProtobufClientInitializer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * @author Chris Chan
 * Create on 2021/4/19 21:06
 * Use for:
 * Explain:
 */
public class ProtobufClient {
    public static void main(String[] args) {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap
                    .group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ProtobufClientInitializer());
            bootstrap.connect("localhost", 8001).sync().channel();

        } catch (Exception e) {

        } finally {
            group.shutdownGracefully();
        }
    }
}

三、测试

首先启动服务器端,再启动客户端。服务器端的控制台打印测试结果。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值