ProtoBuf和Netty的简单使用

快来打我* 2021-09-16 13:26 565阅读 0赞

1096904-20170308110123406-541003583.png

1.pom.xml:

当然,也可建立个java工程把jar包放进去

  1. 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. 3 <modelVersion>4.0.0</modelVersion>
  4. 4 <groupId>netty-demo</groupId>
  5. 5 <artifactId>com.kingdee</artifactId>
  6. 6 <version>0.0.1-SNAPSHOT</version>
  7. 7 <properties>
  8. 8 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  9. 9 <spring.version>3.2.5.RELEASE</spring.version>
  10. 10 <spring.rabbit.version>1.3.5.RELEASE</spring.rabbit.version>
  11. 11 </properties>
  12. 12 <dependencies>
  13. 13 <dependency>
  14. 14 <groupId>org.springframework</groupId>
  15. 15 <artifactId>spring-context</artifactId>
  16. 16 <version>${spring.version}</version>
  17. 17 </dependency>
  18. 18
  19. 19 <!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
  20. 20 <dependency>
  21. 21 <groupId>io.netty</groupId>
  22. 22 <artifactId>netty-all</artifactId>
  23. 23 <version>4.0.23.Final</version>
  24. 24 </dependency>
  25. 25
  26. 26 <!-- https://mvnrepository.com/artifact/log4j/log4j -->
  27. 27 <dependency>
  28. 28 <groupId>log4j</groupId>
  29. 29 <artifactId>log4j</artifactId>
  30. 30 <version>1.2.17</version>
  31. 31 </dependency>
  32. 32
  33. 33 <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
  34. 34 <dependency>
  35. 35 <groupId>commons-logging</groupId>
  36. 36 <artifactId>commons-logging</artifactId>
  37. 37 <version>1.1.1</version>
  38. 38 </dependency>
  39. 39
  40. 40 <dependency>
  41. 41 <groupId>com.google.protobuf</groupId>
  42. 42 <artifactId>protobuf-java</artifactId>
  43. 43 <version>3.0.0</version>
  44. 44 </dependency>
  45. 45 </dependencies>
  46. 46 </project>

2.msg.proto,把它转换成java代码,再拷贝到对应的包下,利用proto.exe工具生成

mgs.proto:

它是传输的实体类,有两个部分,client和service

传输数据时可以直接.来选择调用哪个对象

  1. package com.netty.demo;
  2. message Client {
  3. required string head = 1;
  4. required string body = 2;
  5. }
  6. message Server {
  7. required int32 code=1;
  8. required string message=2;
  9. }

在protoc.exe下面放proto文件,通过命令生成这个传输实体类

1096904-20170308110543531-959890641.png

3.客户端代码:

Client.java:

  1. package com.netty.demo.client;
  2. import io.netty.bootstrap.Bootstrap;
  3. import io.netty.channel.ChannelFuture;
  4. import io.netty.channel.EventLoopGroup;
  5. import io.netty.channel.nio.NioEventLoopGroup;
  6. import io.netty.channel.socket.nio.NioSocketChannel;
  7. public class Client {
  8. public static String host = "127.0.0.1";
  9. public static int port = 8787;
  10. public static void main(String[] args) {
  11. EventLoopGroup worker = new NioEventLoopGroup();
  12. Bootstrap b = new Bootstrap();
  13. b.group(worker);
  14. b.channel(NioSocketChannel.class);
  15. b.handler(new ClientInitializer());
  16. try {
  17. ChannelFuture f = b.connect(host, port).sync();
  18. f.channel().closeFuture().sync();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. } finally {
  22. worker.shutdownGracefully();
  23. }
  24. }
  25. }

复制代码

ClientHandler.java(处理客户端消息发送和收到服务端消息的处理,但一般情况下是不会在这里写发送消息的逻辑的,只是为了写demo,所以把发消息写在这里面)

  1. package com.netty.demo.client;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.channel.SimpleChannelInboundHandler;
  4. import com.google.protobuf.Message;
  5. import com.netty.demo.Msg;
  6. public class ClientHandler extends SimpleChannelInboundHandler<Message> {
  7. /**
  8. *
  9. */
  10. protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
  11. System.out.println("Server say : " + msg.toString());
  12. }
  13. /**
  14. *
  15. */
  16. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  17. System.out.println("Client active ");
  18. Msg.Client msg = Msg.Client.newBuilder().setHead("Content-Type:application/json;charset=UTF-8").setBody("hello world!").build();
  19. ctx.writeAndFlush(msg);
  20. super.channelActive(ctx);
  21. }
  22. @Override
  23. public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  24. System.out.println("Client close ");
  25. super.channelInactive(ctx);
  26. }
  27. }

ClientInitializer.java(初始化Chanel,如解码,加密等),最早的netty传protobuf,是需要手动toByteArrary()把传输对象序列化成二进制流发出去,接收端再手动反序列化还原成传输对象。

但是后来通过设置protubuf编码解码器,就可以自动实现序列化和反序列化,传输时只需要把实体发出去就行了。

  1. package com.netty.demo.client;
  2. import com.netty.demo.Msg;
  3. import io.netty.channel.ChannelInitializer;
  4. import io.netty.channel.socket.SocketChannel;
  5. import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
  6. import io.netty.handler.codec.LengthFieldPrepender;
  7. import io.netty.handler.codec.protobuf.ProtobufDecoder;
  8. import io.netty.handler.codec.protobuf.ProtobufEncoder;
  9. public class ClientInitializer extends ChannelInitializer<SocketChannel> {
  10. protected void initChannel(SocketChannel ch) throws Exception {
  11. // decoded
  12. ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
  13. //这里是收到服务端发过来的消息,所以是对服务端的response解码
  14. ch.pipeline().addLast(new ProtobufDecoder(Msg.Server.getDefaultInstance()));
  15. // encoded
  16. ch.pipeline().addLast(new LengthFieldPrepender(4));
  17. ch.pipeline().addLast(new ProtobufEncoder());
  18. // 注册handler
  19. ch.pipeline().addLast(new ClientHandler());
  20. }
  21. }

复制代码

4.Server端代码:

Server.java

  1. package com.netty.demo.server;
  2. import io.netty.bootstrap.ServerBootstrap;
  3. import io.netty.channel.ChannelFuture;
  4. import io.netty.channel.ChannelOption;
  5. import io.netty.channel.EventLoopGroup;
  6. import io.netty.channel.nio.NioEventLoopGroup;
  7. import io.netty.channel.socket.nio.NioServerSocketChannel;
  8. public class Server {
  9. private static int port = 8787;
  10. public static void main(String[] args) {
  11. EventLoopGroup boss = new NioEventLoopGroup();
  12. EventLoopGroup worker = new NioEventLoopGroup();
  13. ServerBootstrap server = new ServerBootstrap();
  14. server.group(boss, worker);
  15. server.channel(NioServerSocketChannel.class);
  16. server.childHandler(new ServerInitializer());
  17. server.option(ChannelOption.SO_BACKLOG, 128);
  18. server.childOption(ChannelOption.SO_KEEPALIVE, true);
  19. try {
  20. //绑定端口 同步等待成功
  21. ChannelFuture f = server.bind(port).sync();
  22. //等待服务端监听端口关闭
  23. f.channel().closeFuture().sync();
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. } finally {
  27. worker.shutdownGracefully();
  28. boss.shutdownGracefully();
  29. }
  30. }
  31. }

复制代码

ServerHandler.java:

  1. package com.netty.demo.server;
  2. import java.net.InetAddress;
  3. import com.google.protobuf.Message;
  4. import com.netty.demo.Msg;
  5. import com.netty.demo.Msg.Client;
  6. import io.netty.channel.ChannelHandlerContext;
  7. import io.netty.channel.SimpleChannelInboundHandler;
  8. /**
  9. * 处理客户端连接时的handler
  10. *
  11. * @author shizhengchao32677
  12. *
  13. */
  14. public class ServerHandler extends SimpleChannelInboundHandler<Message> {
  15. /**
  16. * 收到客户端发过来的消息
  17. */
  18. protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
  19. // 收到消息直接打印输出
  20. System.out.println(msg.getClass());
  21. Msg.Server response = null;
  22. if(msg instanceof Msg.Client) {
  23. Msg.Client clientMsg = (Client) msg;
  24. System.out.println(ctx.channel().remoteAddress() + " Say : " + clientMsg.getBody());
  25. response = Msg.Server.newBuilder().setCode(0).setMessage("Received client message success").build();
  26. } else {
  27. response = Msg.Server.newBuilder().setCode(-1).setMessage("client message is illegal").build();
  28. System.out.println("client message is illegal");
  29. }
  30. // 返回客户端消息 - 我已经接收到了你的消息
  31. ctx.writeAndFlush(response);
  32. }
  33. /*
  34. * 覆盖 channelActive 方法 在channel被启用的时候触发 (在建立连接的时候)
  35. */
  36. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  37. System.out.println("RamoteAddress : " + ctx.channel().remoteAddress() + " active !");
  38. String welcome = "Welcome to " + InetAddress.getLocalHost().getHostName() + " service!";
  39. Msg.Server response = Msg.Server.newBuilder().setCode(101).setMessage(welcome).build();
  40. ctx.writeAndFlush(response);
  41. super.channelActive(ctx);
  42. }
  43. }

ServerInitializer.java

  1. package com.netty.demo.server;
  2. import io.netty.channel.ChannelInitializer;
  3. import io.netty.channel.socket.SocketChannel;
  4. import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
  5. import io.netty.handler.codec.LengthFieldPrepender;
  6. import io.netty.handler.codec.protobuf.ProtobufDecoder;
  7. import io.netty.handler.codec.protobuf.ProtobufEncoder;
  8. import com.netty.demo.Msg;
  9. public class ServerInitializer extends ChannelInitializer<SocketChannel> {
  10. protected void initChannel(SocketChannel ch) throws Exception {
  11. // decoded
  12. ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
  13. //解码客户端发过来的消息
  14. ch.pipeline().addLast(new ProtobufDecoder(Msg.Client.getDefaultInstance()));
  15. // encoded
  16. ch.pipeline().addLast(new LengthFieldPrepender(4));
  17. ch.pipeline().addLast(new ProtobufEncoder());
  18. // 注册handler
  19. ch.pipeline().addLast(new ServerHandler());
  20. }
  21. }

运行Server.java和Client.java:

  1. Server输出:
  2. RamoteAddress : /127.0.0.1:59693 active !
  3. class com.netty.demo.Msg$Client
  4. /127.0.0.1:59693 Say : hello world!
  5. Clientl输出:
  6. Client active
  7. Server say : code: 101
  8. message: "Welcome to H4UOJJQSF23HQ91 service!"
  9. Server say : code: 0
  10. message: "Received client message success"

发表评论

表情:
评论列表 (有 0 条评论,565人围观)

还没有评论,来说两句吧...

相关阅读

    相关 protobuf简单使用

    一、介绍         首先,protobuf是一个开源项目,而且是后台很硬的开源项目。网上现有的大部分(至少80%)开源项目,要么是某人单干、要么是几个闲杂人等合伙搞。而