netty与rabbitmq整合之netty传输大文件解决

        最近在使用netty和rabbitmq进行开发即时通讯,为什么我会考虑使用这两个呢?首先Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序,而rabbitmq可以实现一端的写入至订阅的队列,并且驱动订阅者消费队列的信息,以达到信息通讯的可靠,满足我的需求。

     针对于我的坑,我简单地说下,本来我是打算制定自己的协议,然后客户端与服务器端都遵循相同的协议进行通讯。最重要的莫过于编码器与解码器,我继承了MessageToMessageCode这个类,形如myclass extends MessageToMessageCodec<ByteBuf,LuckMessage>,其中Message是我定义的规范

@ChannelHandler.Sharable
public class ProtoCodec extends MessageToMessageCodec<ByteBuf,LuckMessage> {

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, LuckMessage message, List<Object> list) throws Exception {

        ByteBuf byteBuf= ByteBufAllocator.DEFAULT.buffer();

        if(message.getContent()!=null){

            byteBuf.writeInt(message.getLuckHeader().getVersion());

            byteBuf.writeInt(message.getLuckHeader().getContentLength());

            byteBuf.writeBytes(message.getLuckHeader().getSessionId().getBytes());

            byteBuf.writeBytes(message.getContent());


        }
        channelHandlerContext.writeAndFlush(byteBuf);
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {

        LuckMessage message=new LuckMessage();
        LuckHeader header=new LuckHeader();
        header.setVersion(byteBuf.readInt());
        header.setContentLength(byteBuf.readInt());
        int length=header.getContentLength();
        byte[] bb = new byte[length];
        byteBuf.readBytes(bb);
        header.setSessionId(new String(bb));
        byte[] b=new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(b);
        message.setContent(b);
        message.setLuckHeader(header);
        list.add(message);
    }
}

这里很协议LuckMessage说到底就是类,然后我直接让它在我的解析器里面解析出来,就没必要Handler器中去解析

ByteBuf了,只要单纯地获取LuckMessage就搞定了,然而照着这样去做的时候会发现,当字节数小于1024的时候,解析很正常;但当字节数大于1024的时候为啥会有异常呢?我解析得好好的。别急,我们测试下,在解析器里我加了测试语句,然后发现居然会重复地打印,是由于如果字节数太长会重复地读取相同的字节吗?经过网上的资料查询以及测试结果表明,就是如此。有个做法就是在解析器里面读完一次然后拼接起来,不过netty官方有提供一个解析器解决了这个问题LengthFieldBasedFrameDecoder解决问题

ByteBuf byteBuf = Unpooled.buffer();
            byteBuf.writeInt("jpg".length());
            byteBuf.writeBytes("jpg".getBytes());
            byteBuf.writeInt(bt.length);
            byteBuf.writeBytes(bt);
            ch.writeAndFlush(byteBuf);

然后在handler解析的时候

public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {

    public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {  // (2)

        Channel incoming = ctx.channel();
        for (Channel channel : channels) {
            channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入\n");
        }
        channels.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {  // (3)
        Channel incoming = ctx.channel();
        for (Channel channel : channels) {
            channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 离开\n");
        }
        channels.remove(ctx.channel());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf)msg;
        int type=byteBuf.readInt();
        byte[] b=new byte[type];
        byteBuf.readBytes(b);
        String st=new String(b);
        System.out.println("类型:"+st);
        int length=byteBuf.readInt();
        System.out.println("长度:"+length);
        byte[] bt=new byte[length];
        byteBuf.readBytes(bt);
        FileAndByte.getFile(bt,"c:","456.jpg");


        // 收到消息直接打印输出
        System.out.println(ctx.channel().remoteAddress() + " Say : " + msg);
        // 返回客户端消息 - 我已经接收到了你的消息
        ctx.writeAndFlush("Received your message !\n");
    }

    /*
     *
     * 覆盖 channelActive 方法 在channel被启用的时候触发 (在建立连接的时候)
     *
     * channelActive 和 channelInActive 在后面的内容中讲述,这里先不做详细的描述
     * */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        System.out.println("RamoteAddress : " + ctx.channel().remoteAddress() + " active !");

        ctx.writeAndFlush( "Welcome to " + InetAddress.getLocalHost().getHostName() + " service!\n");

        super.channelActive(ctx);
    }
}

看完channelRead0中的解析,相信你已经可以解决问题了,然后不要忘记了对于ChannelInitializer中添加 LengthFieldBasedFrameDecoder的解析器,设置参数去百度下解决。

以下参考的网站http://www.jianshu.com/p/8fcca15ea0b9

以上是关于netty的大致介绍,哪里写的出错或者不好,请大牛指正。大家多多交流,下次将交流下rabbitmq以及在spring中使用rabbitmq

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值