apache dubbo 2.7.3 源代码片段 - dubbo帧协议

本文详细介绍了Apache Dubbo的DubboCodec类在解码过程中的实现,包括检查魔法值、解析Header信息、获取数据长度、解码Body等内容,涉及到的关键点有响应状态、请求ID、序列化工具ID等。通过这段代码,可以理解Dubbo协议在处理网络通信时的数据处理逻辑。
摘要由CSDN通过智能技术生成

 

/**
 * ExchangeCodec
 *
 *《Protocol Info》(byte map)
 *
 * 0      1     2     3      4                                                12                     16
 * +------+-----+-----+------+-----+-----+-----+-----+-----+-----+-----+------+-----+-----+-----+-----+
 * | high | low |flag |status|               requestId                        |   contentLen          |
 * +------------+------------+-----------+-----------+-----------+------------+-----------+-----------+
 * |                                          ... ...                                                 |
 * +--------------------------------------------------------------------------------------------------+
 *
 * high: magic high 魔法值高位,固定为:da
 * low: magic low 魔法值低位,固定为:bb
 * flag: 见后面
 * status: 响应状态,只在响应有用
 * requestId: id of request
 * contentLen: length of content
 *
 *
 *
 * 《Flag Byte Info》(one byte,bit map)
 *
 * 0       1       2       3                                       8
 * +-------+-------+-------+-------+-------+-------+-------+-------+
 * |REQUEST| TWOWAY| EVENT |           SERIALIZATION_MASK          |
 * +---------------+-------+---------------------------------------+
 *
 * REQUEST: 1=REQ; 0=RESP;用于标记请求和响应
 * TWOWAY: 1=TWOWAY;1=表示需要响应数据;0=不需要响应数据
 * EVENT: 1=EVENT,如:HEARTBEAT_EVENT,非事件类会用DecodeableRpcInvocation包装请求数据
 * SERIALIZATION_MASK: 序列化工具的ID
 *
 */

 

org.apache.dubbo.rpc.protocol.dubbo.DubboCodec

org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#decode(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.buffer.ChannelBuffer, int, byte[])

@Override
protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header) throws IOException {

    // check magic number. 魔法值
    if (readable > 0 && header[0] != MAGIC_HIGH
            || readable > 1 && header[1] != MAGIC_LOW) {
        int length = header.length;

        // 读满header数据
        if (header.length < readable) {
            header = Bytes.copyOf(header, readable); // 创建新的byte数组并把原来header数据拷贝到新的byte数组
            buffer.readBytes(header, length, readable - length); // 读取数据追加到header
        }

        for (int i = 1; i < header.length - 1; i++) {
            if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) {
                buffer.readerIndex(buffer.readerIndex() - header.length + i);
                header = Bytes.copyOf(header, i);
                break;
            }
        }
        return super.decode(channel, buffer, readable, header);
    }

    // check length.
    if (readable < HEADER_LENGTH) {
        return DecodeResult.NEED_MORE_INPUT;
    }

    // get data length.
    int len = Bytes.bytes2int(header, 12);
    checkPayload(channel, len);

    int tt = len + HEADER_LENGTH;
    if (readable < tt) {
        return DecodeResult.NEED_MORE_INPUT;
    }

    // limit input stream.
    ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len);

    try {
        return decodeBody(channel, is, header); // 解码body
    } finally {
        if (is.available() > 0) {
            try {
                if (logger.isWarnEnabled()) {
                    logger.warn("Skip input stream " + is.available());
                }
                StreamUtils.skipUnusedStream(is);
            } catch (IOException e) {
                logger.warn(e.getMessage(), e);
            }
        }
    }
}

 


org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#decodeBody

@Override
protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {
    byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK);
    // get request id.
    long id = Bytes.bytes2long(header, 4);
    if ((flag & FLAG_REQUEST) == 0) {
        // decode response.
        Response res = new Response(id);
        if ((flag & FLAG_EVENT) != 0) {
            res.setEvent(true);
        }
        // get status.
        byte status = header[3];
        res.setStatus(status);
        try {
            if (status == Response.OK) {
                Object data;
                if (res.isHeartbeat()) {
                    ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
                    data = decodeHeartbeatData(channel, in);
                } else if (res.isEvent()) {
                    ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
                    data = decodeEventData(channel, in);
                } else {
                    DecodeableRpcResult result;
                    if (channel.getUrl().getParameter(DECODE_IN_IO_THREAD_KEY, DEFAULT_DECODE_IN_IO_THREAD)) {
                        result = new DecodeableRpcResult(channel, res, is,
                                (Invocation) getRequestData(id), proto);
                        result.decode();
                    } else {
                        result = new DecodeableRpcResult(channel, res,
                                new UnsafeByteArrayInputStream(readMessageData(is)),
                                (Invocation) getRequestData(id), proto);
                    }
                    data = result;
                }
                res.setResult(data);
            } else {
                ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
                res.setErrorMessage(in.readUTF());
            }
        } catch (Throwable t) {
            if (log.isWarnEnabled()) {
                log.warn("Decode response failed: " + t.getMessage(), t);
            }
            res.setStatus(Response.CLIENT_ERROR);
            res.setErrorMessage(StringUtils.toString(t));
        }
        return res;
    } else {
        // decode request.
        Request req = new Request(id);
        req.setVersion(Version.getProtocolVersion());
        req.setTwoWay((flag & FLAG_TWOWAY) != 0);
        if ((flag & FLAG_EVENT) != 0) {
            req.setEvent(true);
        }
        try {
            Object data;
            ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
            if (req.isHeartbeat()) {
                data = decodeHeartbeatData(channel, in);
            } else if (req.isEvent()) {
                data = decodeEventData(channel, in);
            } else {
                DecodeableRpcInvocation inv;
                if (channel.getUrl().getParameter(DECODE_IN_IO_THREAD_KEY, DEFAULT_DECODE_IN_IO_THREAD)) {
                    inv = new DecodeableRpcInvocation(channel, req, is, proto);
                    inv.decode();
                } else {
                    inv = new DecodeableRpcInvocation(channel, req,
                            new UnsafeByteArrayInputStream(readMessageData(is)), proto);
                }
                data = inv;
            }
            req.setData(data);
        } catch (Throwable t) {
            if (log.isWarnEnabled()) {
                log.warn("Decode request failed: " + t.getMessage(), t);
            }
            // bad request
            req.setBroken(true);
            req.setData(t);
        }

        return req;
    }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值