接上面两篇文章:
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();
}
}
}
三、测试
首先启动服务器端,再启动客户端。服务器端的控制台打印测试结果。