Netty学习笔记(四)Springboot实现自定义协议

背景

工作场合肯定是需要自定义协议的,下面是个用Springboot写的独立的服务端、客户端程序。

上代码

  1. 添加Netty依赖,这里博主同时也消除Tomcat依赖

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
         <exclusions>
             <exclusion>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-tomcat</artifactId>
             </exclusion>
         </exclusions>
     </dependency>
     
     <dependency>
         <groupId>io.netty</groupId>
         <artifactId>netty-all</artifactId>
         <version>4.1.31.Final</version>
     </dependency>
    
  2. 写一个自定义协议的类:

     //这里博主写了个仅有长度和内容的协议
     public class PersonProtocal {
     
     private int length;
     private byte[] content;
    
     public int getLength() {
     		return length;
     	}
    
     public void setLength(int length) {
     		this.length = length;
     	}
    
     public byte[] getContent() {
     		return content;
     	}
    
     public void setContent(byte[] content) {
    		 this.content = content;
     	}
     }
    
  3. 写编码MyPersonEncoder类:

     //该类只有长度+内容
     public class MyPersonEncoder extends MessageToByteEncoder<PersonProtocal> {
     @Override
     protected void encode(ChannelHandlerContext ctx, PersonProtocal msg, ByteBuf out) throws Exception {
     	System.out.println("MyPersonEncoder encode invoked");
     	out.writeInt(msg.getLength());
     	out.writeBytes(msg.getContent());
      	}
      }
    
  4. 写译码MyPersonDecoder类:

     public class MyPersonDecoder  extends ReplayingDecoder<Void> {
     @Override
     protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
     	System.out.println("MyPersonDecoder decode invoked ");
     	int length = in.readInt();
     	byte[] content = new byte[length];
     	in.readBytes(content);
    
     	PersonProtocal personProtocal = new PersonProtocal();
     	personProtocal.setLength(length);
     	personProtocal.setContent(content);
    
     	out.add(personProtocal);
     	}
     }
    

    注:ByteToMessageDecoder 可以在阻塞的i/o模式下实现非阻塞的解码。
    ReplayingDecoder 和ByteToMessageDecoder 最大的不同就是ReplayingDecoder ,不需要判断可用的字节。

  5. 服务端启动类:

    public class EchoServer {
    	private final int port;
    	private Logger log = LoggerFactory.getLogger(this.getClass());
    
    	 public EchoServer(int port)
     	{
    		this.port=port;
    	}
    
    	public void start() throws Exception{
    		final EchoServerHandler serverHandler = new EchoServerHandler();
    		EventLoopGroup group = new NioEventLoopGroup();
     		try
     			{
         			ServerBootstrap serverBootstrap=new ServerBootstrap();
         			serverBootstrap.group(group)
                 			.localAddress(new InetSocketAddress(port))
                 			.channel(NioServerSocketChannel.class)
                 			.childHandler(new ChannelInitializer<SocketChannel>() {
                     			@Override
                     			protected void initChannel(SocketChannel channel) throws Exception {
                         		channel.pipeline().addLast(new MyPersonDecoder());
                         		channel.pipeline().addLast(new MyPersonEncoder());
                         		channel.pipeline().addLast(serverHandler);
                     				}
                			 });
         		ChannelFuture f=serverBootstrap.bind().sync();
         		f.channel().closeFuture().sync();
    			 }
     				finally {
         					group.shutdownGracefully().sync();
     						}
    				}
    			}
    
  6. 服务端Handler类:

     	@ChannelHandler.Sharable   //没写这个,当服务端关闭再连接时会报错Failed to initialize a channel. Closing
     	public class EchoServerHandler extends SimpleChannelInboundHandler<PersonProtocal> {
     	    private int count;
     		@Override
     		protected void channelRead0(ChannelHandlerContext ctx, PersonProtocal msg) throws Exception {
     				System.out.println("服务端接受到的数据:");
     				System.out.println("数据长度:"+msg.getLength());
     				System.out.println("数据内容:"+ new String(msg.getContent(), Charset.forName("utf-8")) );
     				System.out.println("服务端接收到的消息数量:"+(++count));
    
     				String responseMessage = UUID.randomUUID().toString();
     				int responseLength = responseMessage.getBytes(Charset.forName("utf-8")).length;
     				byte[] responseContent = responseMessage.getBytes(Charset.forName("utf-8"));
    					PersonProtocal personProtocal = new PersonProtocal();
     				personProtocal.setLength(responseLength);
    					personProtocal.setContent(responseContent);
     				ctx.writeAndFlush(personProtocal);
     				}
    
     		@Override
     		public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
     				cause.printStackTrace();
     				ctx.close();
     				}
     			}
    
  7. Application,博主没有用tomcat做容器

    		@SpringBootApplication
    		public class Nettyserver3Application implements CommandLineRunner {
    
    		public static void main(String[] args) {
    		SpringApplication.run(Nettyserver3Application.class, args);
    	 		}
    
    		@Override
    		public void run(String... strings) throws Exception {
    			EchoServer echoServer = new EchoServer(7000);
    			echoServer.start();
    			}
    		}
    

———————————————————————我是分割线,下面是客户端部分———————————————————

  1. 编码,解码,协议包都是不变的

  2. 客户端启动类:

     public class EchoClient {
    
     @Value("${netty.host}")
     private String host;
     @Value("${netty.port}")
     private int port;
    
     //@PostConstruct
     public void start() throws Exception {
     	EventLoopGroup group = new NioEventLoopGroup();
    
     try {
         Bootstrap b = new Bootstrap();
         b.group(group).channel(NioSocketChannel.class).remoteAddress(new InetSocketAddress(host, port))
                     .handler(new ChannelInitializer<Channel>() {
                         @Override
                         protected void initChannel(Channel ch) throws Exception {
                             ch.pipeline().addLast(new MyPersonDecoder());
                             ch.pipeline().addLast(new MyPersonEncoder());
                             ch.pipeline().addLast(new EchoClientHandler());
    
                         }
                 });
         ChannelFuture f = b.connect().sync();
         f.channel().writeAndFlush("hello");
    
         f.channel().closeFuture().sync();
     } finally {
         group.shutdownGracefully().sync();
     		}
     	}
     }
    
  3. 客户端Handler类:

     public class EchoClientHandler extends SimpleChannelInboundHandler<PersonProtocal>{
     private int count;
    
     @Override
     public void channelActive(ChannelHandlerContext ctx) throws Exception {
    	// for(int i=0;i<10;i++){
    
         byte[] message={0x10, 0x12, 0x15};
         int length =message.length;
         byte[] content=message;
         
        /* Scanner scanner = new Scanner(System.in);
         System.out.println("请输入:");
         String mess = scanner.nextLine();
         byte[] message = mess.getBytes();
         int length =message.length;
         byte[] content=message;*/
    
       /*    String messaage = "sent from client";
         int length = messaage.getBytes(Charset.forName("utf-8")).length;
         byte[] content = messaage.getBytes(Charset.forName("utf-8"));*/
         
         PersonProtocal personProtocal = new PersonProtocal();
         personProtocal.setLength(length);
         personProtocal.setContent(content);
         ctx.writeAndFlush(personProtocal);
    	// }
     }
    
  4. Application:

     @SpringBootApplication
     public class ClientApplication implements CommandLineRunner {
     @Autowired
     private EchoClient echoclient;
    
     public static void main(String[] args) {
     	SpringApplication.run(ClientApplication.class, args);
     }
     @Bean           //凡是子类及带属性、方法的类都注册Bean到Spring中,交给它管理;
     public EchoClient echoClient(){
     	return new EchoClient();
     }
    
     @Override
     public void run(String... strings) throws Exception {
    		 //EchoClient echoclient = new EchoClient();
     	echoclient.start();
    	 }
     }
    

参考文章 :https://blog.csdn.net/u012150590/article/details/81255567

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值