Java Netty4 基于对象的通信 一

3 篇文章 0 订阅


前言:



最近因为新项目的需要,需要使用netty这种框架来实现通信,现在将学习的部分心得编写出来。
以下代码均是在Netty4的基础上做的测试,在Netty3上无法正常运行(这也是netty做的不好的地方,这种在代码迁移的时候会非常的痛苦)

下面几个类主要是对底层Netty做的封装,便于新手使用的.

先不说那么多废话了,直接codes ,看起来比较容易懂得



一:传输对象BaseObjBean对象


目的:先不说那么多,直接看代码
/**
 * 
 * 基类,在传输的类上,都需要继承之该类 .
 * 
 * @author rocky
 *
 */
public class BaseObjBean implements Serializable {

private static final long serialVersionUID = 1L;

/**
* 根据自己的实现业务,选择更合适自己的基类业务去实现 ...
*/

}


二:业务处理BusinessHandler 对象


目的:主要是对传输过来的对象做业务处理
/**
 * 
 * 业务类的编写.
 * 
 * @author rocky
 *
 */
public class BusinessHandler extends ChannelInboundHandlerAdapter {


private BaseObjBean bean;

public BusinessHandler(BaseObjBean bean){
this.bean = bean;
}

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        bean = (BaseObjBean) msg;
        msg = "BusinessHandler read msg from client :" + bean;
        System.out.println(msg);
        msg = "服务端返回的消息是:OK !";
        ctx.write(msg);
        ctx.channel().write(msg);
        ctx.channel().writeAndFlush(msg);
        ctx.writeAndFlush(msg);
    }
 
    /**
     * 消息读取
     * 
     * @param ctx
     * 
     * @param bean
     * @throws Exception
     */
    protected void messageReceived(ChannelHandlerContext ctx, BaseObjBean bean) throws Exception {
    ctx.channel().writeAndFlush("server 读取client发送来的信息成功了...,className = "+bean.getClass().getName());
    }
    
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }
     
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
         ctx.close();
    }


}


三:传输对象ClientInitHandler


目的:用来传输对象的
 /**
  * 
  * 初始化的handler(传输对象)
  * 
  * @author rocky
  *
  */
public class ClientInitHandler extends ChannelInboundHandlerAdapter {

private BaseObjBean bean;

public ClientInitHandler(BaseObjBean bean) {
this.bean = bean;
}

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.write(bean);  //该对象已经给序列化了
        ctx.flush();
    }
    
    @Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
    ctx.writeAndFlush("client接收到服务器返回的消息:"+msg);
    System.out.println("client接收到服务器返回的消息:"+msg);
}
    
}


四:基础NettyBaseClient对象



目的:主要是来连接服务端,传输数据的

/**
 * 
 * 客户端的编写.
 * 
 * @author rocky
 *
 */
public class NettyBaseClient {

private BaseObjBean bean;

public NettyBaseClient(BaseObjBean bean){
this.bean = bean;
}

/**
* 连接的构建.

* @param host
* @param port
* @throws Exception
*/
    public void connect(String host, int port) throws Exception {
    EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap(); 
            b.group(workerGroup); 
            b.channel(NioSocketChannel.class); 
            b.option(ChannelOption.SO_KEEPALIVE, true); 
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    //编码字节设置
                    ch.pipeline().addLast(new ObjEncoder());
                    //
                    ch.pipeline().addLast(new ClientInitHandler(bean));
                }
            });
 
            ChannelFuture f = b.connect(host, port).sync();
            if (f.isSuccess()) {
System.out.println("客户端创建好了...");
}
            
            SocketChannel  channel = (SocketChannel) f.channel();
            
            System.out.println("服务端返回的数据是:"+channel.metadata().toString());
            
            //关闭
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
 
    
    /**
     * 
     * 连接的构建.
     *
     *@param host
     * @param port
     * @param handler:自己实现的handler.
     * @throws Exception
     */
    public void connect(String host, int port,final ChannelHandler handler ) throws Exception {
    EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap(); 
            b.group(workerGroup); 
            b.channel(NioSocketChannel.class); 
            b.option(ChannelOption.SO_KEEPALIVE, true); 
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    //编码字节设置
                    ch.pipeline().addLast(new ObjEncoder());
                    //
                    ch.pipeline().addLast(handler);
                }
            });
 
            ChannelFuture f = b.connect(host, port).sync();
            if (f.isSuccess()) {
            SocketChannel  channel = (SocketChannel) f.channel();
System.out.println("客户端创建好了...");
}
            //关闭
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
 
}


五:服务基类 NettyBaseServer 对象



目的:主要是用来连接客户端服务


/**
 * 服务端的编写
 * 
 * @author rocky
 *
 */
public class NettyBaseServer {


private BaseObjBean bean;

public NettyBaseServer(BaseObjBean bean){
this.bean = bean;
}

/**
* 开始方法.

* @param port
* @throws Exception
*/
    public void start(int port) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); 
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap server = new ServerBootstrap(); 
            server.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 
                    .childHandler(new ChannelInitializer<SocketChannel>() { 
                                @Override
                                public void initChannel(SocketChannel ch) throws Exception {
                                    //解码处理操作.
                                    ch.pipeline().addLast(new ObjDecoder());
                                    //业务处理的主要实现类.
                                    ch.pipeline().addLast(new BusinessHandler(bean));
                                }
                            }).option(ChannelOption.SO_BACKLOG, 128) 
                    .childOption(ChannelOption.SO_KEEPALIVE, true); 
            //绑定端口,得到对象
            ChannelFuture f = server.bind(port).sync(); 
            if (f.isSuccess()) {
System.out.println(" NettyBaseServer 服务创建完成了...");
}
            
            //关闭连接.
            f.channel().closeFuture().sync();
            
        } finally {
        //关闭集合
        workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }




/**
* 开始方法.

* @param port
* @throws Exception
*/
    public void start(int port,final ChannelHandler handler) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); 
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap server = new ServerBootstrap(); 
            server.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 
                    .childHandler(new ChannelInitializer<SocketChannel>() { 
                                @Override
                                public void initChannel(SocketChannel ch) throws Exception {
                                    //解码处理操作.
                                    ch.pipeline().addLast(new ObjDecoder());
                                    //业务处理的主要实现类.
                                    ch.pipeline().addLast(handler);
                                }
                            }).option(ChannelOption.SO_BACKLOG, 128) 
                    .childOption(ChannelOption.SO_KEEPALIVE, true); 
            //绑定端口,得到对象
            ChannelFuture f = server.bind(port).sync(); 
            if (f.isSuccess()) {
//System.out.println("服务创建完成了...");
}
            f.channel().writeAndFlush(" NettyBaseServer 服务创建完成了...");
            //关闭连接.
            f.channel().closeFuture().sync();
            
        } finally {
        //关闭集合
        workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}


六:对象转换ObjConverter对象



目的:负责将object对象转换为字节;或者将字节转化为object对象的


/**
 * 
 * 字节和obj对象的转变.
 * 
 * @author rocky
 *
 */
public class ObjConverter {
 
/**
* 字节到obj

* @param bytes
* @return
*/
    public static Object byteToObject(byte[] bytes) {
        Object obj = null;
        ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
        ObjectInputStream oi = null;
        try {
            oi = new ObjectInputStream(bi);
            obj = oi.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bi.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                oi.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return obj;
    }
 
    /**
     * 
     * obj到字节的转换.
     * 
     * @param obj
     * @return
     */
    public static byte[] objectToByte(Object obj) {
        byte[] bytes = null;
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = null;
        try {
            oo = new ObjectOutputStream(bo);
            oo.writeObject(obj);
            bytes = bo.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bo.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                oo.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }
    
    /**
     * 
     * 读取netty中的ByteBuf对象
     * 
     * @param datas
     * @return
     */
    public static byte[] read(ByteBuf datas) {
        byte[] bytes = new byte[datas.readableBytes()];
        datas.readBytes(bytes);
        return bytes;
    }
}


七:对象化



目的:将对象进行转化


/**
 * 
 * 将字节转换为对象
 * 
 * @author rocky
 *
 */
public class ObjDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        Object obj = ObjConverter.byteToObject(ObjConverter.read(in));
        out.add(obj);
    }
 
}


/**
 * 
 * 将object对象转换成字节传输.
 * 
 * @author rocky
 *
 */
public class ObjEncoder extends MessageToByteEncoder<Object> {
 
    @Override
    protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
        byte[] datas = ObjConverter.objectToByte(msg);
        out.writeBytes(datas);
        ctx.flush();
    }
}


以上对底层的包装就已经完成,后续会介绍如何使用。

其实这里面涉及的知识还是比较多的,而且他们之间的联系也比较的密切,本质上:

还是socket的通信,只不过是做了很多的封装的工作.... 不难,不难




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值