Netty【3】编解码技术 - Marshalling

                                      Netty编解码技术 - Marshalling

 

编解码技术,说白了就是java序列化技术,序列化目的就两个:

  • 第一进行网络传输,
  • 第二对象持久化。

虽然我们可以使用java进行对象序列化,netty去传输,但是java序列化的硬伤太多,比如java序列化没法跨语言、序列化后码流太大、序列化性能太低等等..
主流的编解码框架

  • JBoss的Marshalling包 ( 适合 Java  与  Java 之间的传输)
  • google的Protobuf
  • 基于Protobuf的Kyro
  • MessagePack框架

Marshalling适合 Java  与  Java 之间的传输,它的好处是可以直接把消息转成我们需要的对象.

 

在 Handler那块加上编写好的  编码,解码方法。

 .childHandler(new ChannelInitializer<SocketChannel>() {
   @Override
   protected void initChannel(SocketChannel ch) throws Exception {
      // 解码
      ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
      // 编码
      ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
      ch.pipeline().addLast(new ServerHandler());
   }
});

创建两个对象: Request , Response 用于请求数据和响应数据

Request

@Data
public class Request implements Serializable {

	private static final long serialVersionUID = 8743187299189428700L;

	private String id;
	
	private String name;
	
	private String requestMessage;

	// 附件,比如图片...
	private byte[] attachment;

Respone

@Data
public class Response implements Serializable {

	private static final long serialVersionUID = -4639347903121316828L;
	
	private String id;
	
	private String name;
	
	private String responseMessage;

编写

MarshallingCodeCFactory  编解码方法
public final class MarshallingCodeCFactory {

    /**
     * 	创建Jboss Marshalling解码器MarshallingDecoder
     * @return MarshallingDecoder
     */
    public static MarshallingDecoder buildMarshallingDecoder() {
    	//	首先通过Marshalling工具类的通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
		final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
		//	创建了MarshallingConfiguration对象,配置了版本号为5 
		final MarshallingConfiguration configuration = new MarshallingConfiguration();
		configuration.setVersion(5);
		//	根据marshallerFactory和configuration创建provider
		UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
		//	构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
		MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024 * 1024 * 1);
		return decoder;
    }

    /**
     * 	创建Jboss Marshalling编码器MarshallingEncoder
     * @return MarshallingEncoder
     */
    public static MarshallingEncoder buildMarshallingEncoder() {
		final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
		final MarshallingConfiguration configuration = new MarshallingConfiguration();
		configuration.setVersion(5);
		MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
		//	构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
		MarshallingEncoder encoder = new MarshallingEncoder(provider);
		return encoder;
    }
}

然后在 server , client 使用 刚刚写的  MarshallingCodeCFactory 的编解码方法

server

public class Server {

	public static void main(String[] args) throws Exception {
		
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup workGroup = new NioEventLoopGroup();
		
		ServerBootstrap sb = new ServerBootstrap();
		sb.group(bossGroup, workGroup)
			.channel(NioServerSocketChannel.class)
			 .option(ChannelOption.SO_BACKLOG, 1024)
			 .childOption(ChannelOption.TCP_NODELAY, true)
			 .childOption(ChannelOption.SO_RCVBUF, 1024 * 32)
			 .childOption(ChannelOption.SO_SNDBUF, 1024 * 32)
			 .childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					// 解码
					ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
					// 编码
					ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
					ch.pipeline().addLast(new ServerHandler());
				}
			});
			//服务器端绑定端口并启动服务
			ChannelFuture cf = sb.bind(8765).sync();
			//使用channel级别的监听close端口 阻塞的方式
			cf.channel().closeFuture().sync();
			
			bossGroup.shutdownGracefully();
			workGroup.shutdownGracefully();
			
		
	}
	
}

client.

public class Client {

	
	public static void main(String[] args) throws Exception {
		
		//1. 创建两个线程组: 只需要一个线程组用于我们的实际处理(网络通信的读写)
		EventLoopGroup workGroup = new NioEventLoopGroup();
		
		//2 通过辅助类去构造server/client
		Bootstrap b = new Bootstrap();
		b.group(workGroup)
		 .channel(NioSocketChannel.class)
		 .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
		 .option(ChannelOption.SO_RCVBUF, 1024 * 32)
		 .option(ChannelOption.SO_SNDBUF, 1024 * 32)
		 .handler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel ch) throws Exception {
				ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
				ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
				ch.pipeline().addLast(new ClientHandler());	
			}
		});
		//	服务器端绑定端口并启动服务
		ChannelFuture cf = b.connect("127.0.0.1", 8765).syncUninterruptibly();
		//	写出实际的对象数据
		
		for(int i =0; i < 10; i ++) {
			Request req = create(i);
			cf.channel().writeAndFlush(req);
		}

		
		cf.channel().closeFuture().sync();
		workGroup.shutdownGracefully();
		
	}
	
	private static Request create(int seq) throws Exception {
		Request request = new Request();
		request.setId(seq + "");
		request.setName("named:" + seq);
		request.setRequestMessage("messaged:" + seq);
		System.out.println("getProperty:"+System.getProperty("user.dir"));
    	String path = System.getProperty("user.dir") + File.separatorChar + "sources" + File.separatorChar + "001.jpg";
    	FileInputStream fis = new FileInputStream(new File(path));
    	byte[] data = new byte[fis.available()];
    	fis.read(data);
    	fis.close();
    	request.setAttachment(GzipUtils.gzip(data));
    	return request;
	}
	

ServerHandler

package com.bfxy.netty.marshalling;

import java.io.File;
import java.io.FileOutputStream;


import com.bfxy.netty.utils.GzipUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
    	System.err.println("server channel active..");
    }
    
    /**
     * 真正的数据最终会走到这个方法进行处理
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 读取客户端的数据
    	// 使用Marshalling的方便之处,可以直接转换成我们创建的对象。
    	Request req = (Request)msg;
    	System.err.println("Server: " + req.getId() + ", " + req.getName() + ", " + req.getRequestMessage());
    	// 假设传过来的数据是压缩的, 通过ungzip解压缩成一个 byte 数组
    	byte[] attachment = GzipUtils.ungzip(req.getAttachment());
		System.out.println("dir : "+System.getProperty("user.dir") );
    	String path = System.getProperty("user.dir") + File.separatorChar + "receive" + File.separatorChar + "001.jpg";
    	FileOutputStream fos = new FileOutputStream(path);
    	fos.write(attachment);
    	fos.close();
    	
    	Response resp = new Response();
    	resp.setId(req.getId());
    	resp.setName("resp" + req.getName());
    	resp.setResponseMessage("响应内容: " + req.getRequestMessage());
    	ctx.writeAndFlush(resp);
    	
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.fireExceptionCaught(cause);
    }
    
    
}

ClientHandler

package com.bfxy.netty.marshalling;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;

public class ClientHandler extends ChannelInboundHandlerAdapter {


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
    	System.err.println("client channel active..");
    }
    
    /**
     * 真正的数据最终会走到这个方法进行处理
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    	try {
        	ByteBuf buf = (ByteBuf) msg;
            byte[] request = new byte[buf.readableBytes()];
            buf.readBytes(request);
            String requestBody = new String(request, "utf-8");
            System.err.println("Client: " + requestBody);			
		} finally {
			ReferenceCountUtil.release(msg);
		}
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.fireExceptionCaught(cause);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Netty-WebSocket-Spring-Boot-Starter是一个用于将Websocket集成到Spring Boot应用程序中的库。它使用Netty作为底层框架,提供了一种快速和可靠的方式来处理异步通信。 这个库提供了一种简单的方法来创建Websocket端点,只需要使用注释和POJO类即可。在这些端点上可以添加动态的事件处理程序,以处理连接、断开连接和消息事件等。 此外,Netty-WebSocket-Spring-Boot-Starter还包括了一些安全性的特性,如基于令牌的授权和XSS保护,可以帮助您保持您的Websocket应用程序安全。 总的来说,Netty-WebSocket-Spring-Boot-Starter提供了一种快速和易于使用的方式来构建Websocket应用程序,使得它成为应用程序开发人员的有用工具。 ### 回答2: netty-websocket-spring-boot-starter 是一个开源的 Java Web 开发工具包,主要基于 Netty 框架实现了 WebSocket 协议的支持,同时集成了 Spring Boot 框架,使得开发者可以更加方便地搭建 WebSocket 服务器。 该工具包提供了 WebSocketServer 配置类,通过在 Spring Boot 的启动配置类中调用 WebSocketServer 配置类,即可启动 WebSocket 服务器。同时,该工具包还提供了多种配置参数,如端口号、URI 路径、SSL 配置、认证配置等等,可以根据业务需求进行自定义配置。 此外,该工具包还提供了一些可扩展的接口和抽象类,如 WebSocketHandler、ChannelHandlerAdapter 等,可以通过继承和实现这些接口和抽象类来实现业务逻辑的处理和拓展。 总的来说,netty-websocket-spring-boot-starter 提供了一个高效、简单、易用的 WebSocket 服务器开发框架,可以减少开发者的开发成本和工作量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值