Netty4.x实战(二) 对象传递

在上一篇文章对Netty做了一个简要的介绍,并通过Netty实现了server-client端的字符串传输。在实际开发中不可避免的会遇到传输对象的情况,本篇通过一个简单的例子展示如何通过Netty来传输对象。

POJO类

1.首先我们定义一个User对象:

package com.ricky.codelab.netty.model;

import java.io.Serializable;

public class User implements Serializable {
    /** * */
    private static final long serialVersionUID = 1L;

    private long id;
    private String name;
    private int age;
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
    }

}

注意:User类一定要实现 java.io.Serializable 接口,表示我们使用JDK内置的序列化机制来对User进行序列化和反序列化。

服务端程序

POJOTranferServer.java

package com.ricky.codelab.netty.ch2;

import com.ricky.codelab.netty.util.Constant;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

public class POJOTranferServer {

    private final int port;

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

    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup 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) throws Exception {
                            ch.pipeline().addLast(new ObjectEncoder(),
                                    new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)),
                                    new POJOTransferServerHandler());
                        }
                    });

            // Bind and start to accept incoming connections.
            b.bind(port).sync().channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {

        new POJOTranferServer(Constant.PORT).run();
    }
}

Netty4内置了ObjectEncoder和ObjectDecoder类来帮助我们将Object转换为byte数组。

package com.ricky.codelab.netty.ch2;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class POJOTransferServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {

        System.out.println("server receive:"+msg);
        ctx.writeAndFlush(msg);
    }

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

}

客户端程序

POJOTransferClient.java

package com.ricky.codelab.netty.ch2;

import java.util.ArrayList;
import java.util.List;

import com.ricky.codelab.netty.model.User;
import com.ricky.codelab.netty.util.Constant;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

public class POJOTransferClient {
    private String host;
    private int port;
    private List<User> message;

    public POJOTransferClient(String host, int port, List<User> message) {
        this.host = host;
        this.port = port;
        this.message = message;
    }

    public void send() throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap();
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        try {
            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ObjectEncoder(),
                                    new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)),
                                    new POJOTransferClientHandler(message));
                        }
                    });

            ChannelFuture future = bootstrap.connect(host, port).sync();

            future.channel().closeFuture().sync();
        } finally {
            eventLoopGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {

        final List<User> message = new ArrayList<>();
        for(int i=0;i<5;i++){

            User user = new User();
            user.setId(i+1);
            user.setName("Ricky P"+i);
            user.setAge(20+i);

            message.add(user);
        }

        new POJOTransferClient(Constant.HOST, Constant.PORT, message).send();
    }
}
package com.ricky.codelab.netty.ch2;

import java.util.List;

import com.ricky.codelab.netty.model.User;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class POJOTransferClientHandler extends ChannelInboundHandlerAdapter {

    private final List<User> message;

    /** * Creates a client-side handler. */
    public POJOTransferClientHandler(List<User> message) {
        this.message = message;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // Send the message to Server
        super.channelActive(ctx);
        System.out.println("client send message");
        ctx.writeAndFlush(message);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        // you can use the Object from Server here
        System.out.println("client receive:"+msg);
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {

        cause.printStackTrace();
        ctx.close();
    }
}

总结

本例中从客户端发送消息到服务端 属于单向发消息,所以需要在客户端配置编码,服务端解码。如果双向收发,则需要客户端&服务器 都需要配置Encoder和Decoder。

另外, 需要注意的是 注册到Server ChannelPipeline中的handler是有顺序之分的,如果颠倒一下注册顺序导致的结果就是:先进入我们自己的handler,再进行解码,这自然是不行的,会强转失败。

最后,本例中使用Java内置的序列化机制对对象进行序列化和反序列化后再进行传输,当然,我们也可以使用其他序列化机制,例如:kryo、hessian、protobuf等。

源代码下载

点此下载源代码


参考文档:user-guide-for-4.x

你可能感兴趣的:(netty,nio)