Анализ исходного кода Dubbo — распаковка и вставка
Про распаковку и вклейку
Что касается распаковки и приклеивания, на самом деле это явление, которое происходит, когда ссылка TCP отправляет данные.Эта статья не будет подробно объяснять, но в основном для того, чтобы увидеть, как dubbo справляется с этим явлением (dubbo не использует декодер в родной сети), и Он основан на собственном стеке протоколов для реализации собственныхENCODER
/DECODER
,
Если интересно, загляните сюдаНетти решает распаковку и приклеивание.
dubbo разборка/заклейка входа пакета
Вход находится в Дуббо.NettyCodecAdapter
, который содержитencoder
а такжеdecoder
Для соответствующего определения, давайте посмотрим на соответствующие части распаковки.Давайте сначала посмотрим на первую часть:
com.alibaba.dubbo.remoting.buffer.ChannelBuffer message;
if (buffer.readable()) {
if (buffer instanceof DynamicChannelBuffer) {
buffer.writeBytes(input.toByteBuffer());
message = buffer;
} else {
int size = buffer.readableBytes() + input.readableBytes();
message = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.dynamicBuffer(
size > bufferSize ? size : bufferSize);
message.writeBytes(buffer, buffer.readableBytes());
message.writeBytes(input.toByteBuffer());
}
} else {
message = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.wrappedBuffer(
input.toByteBuffer());
}
Сначала определите, есть ли в буфере данные для чтения, и если да, объедините сообщения, чтобы получить сообщение, а затем проанализируйте его.
Продолжайте смотреть на часть синтаксического анализа:
do {
saveReaderIndex = message.readerIndex();
try {
msg = codec.decode(channel, message);
} catch (IOException e) {
buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
throw e;
}
if (msg == Codec2.DecodeResult.NEED_MORE_INPUT) {
message.readerIndex(saveReaderIndex);
break;
} else {
if (saveReaderIndex == message.readerIndex()) {
buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
throw new IOException("Decode without read data.");
}
if (msg != null) {
Channels.fireMessageReceived(ctx, msg, event.getRemoteAddress());
}
}
} while (message.readable());
Вы можете видеть, что это цикл, обрабатывающий сообщение до тех пор, пока оно не станет нечитаемым. Как видите, индекс считывателя сначала сохраняется для отката, а затем вводитсяdecoder
, вотDubboCountCodec
, обратите внимание здесь:DubboCountCodec
Только один полный стек протоколов dubbo (илиNEED_MORE_INPUT
):
int save = buffer.readerIndex();
MultiMessage result = MultiMessage.create();
do {
Object obj = codec.decode(channel, buffer);
if (Codec2.DecodeResult.NEED_MORE_INPUT == obj) {
buffer.readerIndex(save);
break;
} else {
result.addMessage(obj);
logMessageLength(obj, buffer.readerIndex() - save);
save = buffer.readerIndex();
}
} while (true);
if (result.isEmpty()) {
return Codec2.DecodeResult.NEED_MORE_INPUT;
}
if (result.size() == 1) {
return result.get(0);
}
return result;
Вот текущийbuffer
Индекс чтения также для последующего отката (откат здесь не во внешнем слоеbuffer
, чтобы различать здесь). можно увидеть, когдаdecode
то, что возвращаетсяNEED_MORE_INPUT
означает текущийbuffer
Недостаточно данных в середине, и стек протоколов dubbo не может быть полностью разобран.buffer
Индекс чтения откатывается к ранее подготовленному индексу и выходит из цикла, возвращая результат.
Продолжайте смотреть здесьcodec.decode
, и, наконец, находитExchangeCodec
изdecode
Medium, или сегментированный, мы его сначала проигнорировали, это даббо параtelnet
служба поддержки:
// 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;
}
Здесь есть два случая:
- Читаемая длина меньше длины заголовка протокола, что указывает: читаемого поля недостаточно для объема данных заголовка протокола, возврат
DecodeResult.NEED_MORE_INPUT
. - Текущий буфер содержит полный заголовок сообщения, получает длину полезной нагрузки, находит ее читаемую длину и не содержит данных всего стека протоколов, возвращает
DecodeResult.NEED_MORE_INPUT
. - В противном случае, это означает, что включен хотя бы один стек протоколов, затем происходит парсинг данных dubbo, конечно, после чтения могут остаться данные.
Вернемся ко второму фрагменту кода, если msgNEED_MORE_INPUT
, затем поставьтеreaderIndex
откат. Конец цикла:
if (message.readable()) {
message.discardReadBytes();
buffer = message;
} else {
buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
}
NettyChannel.removeChannelIfDisconnected(ctx.getChannel());
Если оно доступно для чтения, отбрасываем прочитанные байты, а затем кешируем оставшуюся информацию сообщения в буфере для следующего чтения.Пока что мы знаем, зачем dubbo нужно реализовывать собственную распаковку и залипание:Dubbo需要解析自己独有的协议栈,而默认的方式不符合dubbo的解析方式
.