netty序列化实现

对象序列化, 目的是为了实现对象的网络传输和本地持久化  
如果使用java的序列化, 码流较大. 因此多用FastjsonSerialize, KryoSerialize,FSTSerialize等  
在本例中使用FSTSerialize进行编解码传输javabean。

一,导入依赖jar

<dependencies>
        <!-- Netty依赖包
        https://mvnrepository.com/artifact/io.netty/netty-all -->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.25.Final</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>
        <!--fst序列化-->
        <dependency>
            <groupId>de.ruedigermoeller</groupId>
            <artifactId>fst</artifactId>
            <version>2.52</version>
        </dependency>

        <!--监控本机cpu,内存等信息-->
        <dependency>
            <groupId>org.fusesource</groupId>
            <artifactId>sigar</artifactId>
            <version>1.6.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <useSystemClassLoader>false</useSystemClassLoader>
                </configuration>
            </plugin>
        </plugins>
    </build>

二,服务端编码

public class Server {

    private final int port;

    public Server(int port) {
        this.port = port;
    }

    public static void main(String[] args) throws Exception {
        int port = 8081;
        new Server(port).start();
    }

    public void start() throws Exception {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ch.pipeline()
                                    // 添加编解码. 发送自定义的类型, 而Handler的方法接收的msg参数的实际类型也是相应的自定义类了
                                    .addLast(new TinyDecoder(Request.class))
                                    .addLast(new TinyEncoder(Response.class))
                                    .addLast(new ServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            ChannelFuture f = b.bind(port).sync();
            System.out.println(Server.class.getName() + " 服务器端开启并监听端口号: " + f.channel().localAddress());
            f.channel().closeFuture().sync();
        } finally {
            //释放 channel 和 块,直到它被关闭
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}

public class ServerHandler extends SimpleChannelInboundHandler<Request> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Request request) throws Exception {
        System.out.println("服务端接收到的消息 : " + request.getRequestId());
        System.out.println("服务端接收到的消息 : " + request.getParameters().toString());
        System.out.println("服务端接收到的消息 : " + request.getClass());
        Response response = new Response();
        response.setRequestId(2L);
        response.setError("success");
        User user = new User();
        user.setUsername("测试");
        user.setPassword("1234");
        user.setAge(21);
        response.setResult(user);
        //addListener是非阻塞的,异步执行。它会把特定的ChannelFutureListener添加到ChannelFuture中,然后I/O线程会在I/O操作相关的future完成的时候通知监听器。
        ctx.writeAndFlush(response).addListener((ChannelFutureListener) channelFuture ->
                System.out.println("接口响应:" + request.getRequestId())
        );
    }
}

三,客户端编码

public class Client {
    private final String host;
    private final int port;

    public Client(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public static void main(String[] args) throws Exception {
        final String host = "127.0.0.1";
        final int port = 8081;

        new Client(host, port).start();
    }

    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<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch)
                                throws Exception {
                            ch.pipeline()
                                    // 添加编解码. 发送自定义的类型, 而Handler的方法接收的msg参数的实际类型也是相应的自定义类了
                                    .addLast(new TinyEncoder(Request.class))
                                    .addLast(new TinyDecoder(Response.class))
                                    .addLast(new ClientHandler());
                        }
                    });

            ChannelFuture f = b.connect().sync();
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully().sync();
        }
    }
}

public class ClientHandler extends SimpleChannelInboundHandler<Response> {

    /**
     * 通道注册
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
    }

    /**
     * 服务器的连接被建立后调用
     * 建立连接后该 channelActive() 方法被调用一次
     *
     * @param ctx
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        Request request = new Request();
        request.setRequestId(3L);
        User user = new User();
        user.setUsername("测试客户端");
        user.setPassword("4567");
        user.setAge(21);
        request.setParameters(user);
        //当被通知该 channel 是活动的时候就发送信息
        ctx.writeAndFlush(request);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Response response) throws Exception {
        System.out.println("服务器发来消息 : " + response.getRequestId());
        System.out.println("服务器发来消息 : " + response.getError());
        System.out.println("服务器发来消息 : " + response.getResult().toString());
    }

    /**
     * 捕获异常时调用
     *
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,
                                Throwable cause) {
        //记录错误日志并关闭 channel
        cause.printStackTrace();
        ctx.close();
    }

}

四,通用封装类

public class FstSerializer {
    private static FSTConfiguration conf = FSTConfiguration.createDefaultConfiguration();

    /**
     * 反序列化
     *
     * @param data
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T deserialize(byte[] data, Class<T> clazz) {
        return (T) conf.asObject(data);
    }

    /**
     * 序列化
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> byte[] serialize(T obj) {
        return conf.asByteArray(obj);
    }
}

public class TinyDecoder extends ByteToMessageDecoder {
    private Class<?> genericClass;

    public TinyDecoder(Class<?> genericClass) {
        this.genericClass = genericClass;
    }

    /**
     * 解码
     *
     * @param ctx
     * @param in
     * @param out
     */
    @Override
    public final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        int size = in.readableBytes();
        byte[] data = new byte[size];
        in.readBytes(data);
        Object obj = FstSerializer.deserialize(data, genericClass);
        out.add(obj);
    }

}
 

@ChannelHandler.Sharable
public class TinyEncoder extends MessageToByteEncoder {
    private Class<?> genericClass;

    public TinyEncoder(Class<?> genericClass) {
        this.genericClass = genericClass;
    }

    /**
     * 编码
     * @param ctx
     * @param in
     * @param out
     * @throws Exception
     */
    @Override
    public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) {
        if (genericClass.isInstance(in)) {
            byte[] data = FstSerializer.serialize(in);
            out.writeBytes(data);
        }
    }

}
 

public class Request implements Serializable {
    private static final long serialVersionUID = -2747321595912488569L;
    private Long requestId;
    private Object parameters;

//get set tostring方法
}

public class Response implements Serializable {
    private static final long serialVersionUID = -3136380221020337915L;
    private Long requestId;
    private String error;
    private Object result;
   
    //get set toString
    
}
 

发布了23 篇原创文章 · 获赞 0 · 访问量 194

猜你喜欢

转载自blog.csdn.net/liuerchong/article/details/105178704