#go #tcp #minecraft
#Вперед #tcp #Minecraft
Вопрос:
Я новичок в Golang. И в последнее время у меня возникла проблема с чтением пакетов из клиентов Minecraft.
Моя программа считывает пакеты из соединения таким образом.
player := amp;Player{
conn: conn,
state: HANDSHAKING,
io: amp;ConnReadWrite{
rdr: bufio.NewReader(conn),
wtr: bufio.NewWriter(conn),
},
inaddr: InAddr{
"",
0,
},
keepalive: 0,
compression: false
}
func (player *Player) ReadVarInt() (i int, err error) {
val, _ := binary.ReadUvarint(player.io)
return int(val), nil
}
Он работал правильно, когда соединение только что было установлено, но позже он не может правильно прочитать идентификатор пакета.
Я работал несколько дней, и я попытался переписать его, чтобы скопировать wiki.vg это решение, но казалось, что оно не работает
PS: Моя копия и оригинал
val, length := 0, 0
for {
current, err := player.io.ReadByte()
if err != nil {
return 0, err
}
val |= int((current amp; 0x7F) << (length * 7))
length = 1
if length > 5 {
return 0, errors.New(fmt.Sprintf("%s: VarInt is too big", player.name))
}
if valamp;0x80 != 0x80 {
break
}
}
return int(val), nil
int value = 0;
int length = 0;
byte currentByte;
while (true) {
currentByte = readByte();
value |= (currentByte amp; 0x7F) << (length * 7);
length = 1;
if (length > 5) {
throw new RuntimeException("VarInt is too big");
}
if ((value amp; 0x80) != 0x80) {
break;
}
}
return value;
Комментарии:
1. я немного смущен оригиналом. во-первых, значение равно (currentByteamp; 0x7F), что означает, что старший значащий бит обнуляется. Затем (значение amp; 0x80) пытается прочитать указанный самый значимый бит, которого больше нет. Мне кажется, это должно быть currentByte amp; 0x80, а не value amp; 0x80.
2. по крайней мере, здесь код проверяет currentByte на предмет того, установлен ли старший значащий бит; и здесь тоже, поэтому я думаю, что ваш оригинал неверен.
Ответ №1:
Код в wiki неверен.
Строка ((value amp; 0x80) != 0x80)
должна быть ((currentByte amp; 0x80) != 0x80)
Кодирование работает следующим образом: число (или что-то еще) делится на 7 битных блоков. затем в каждом байте старший значащий бит (MSB) указывает, где нужно больше байтов, а остальные кодируют число.
Строка value |= (currentByte amp; 0x7F) << (length * 7);
в основном обнуляет MSB (0x7F — это маска для взятия последних семи битов, т. Е. Всех, Кроме MSB, из байта). Проверяется ((value amp; 0x80) != 0x80)
, является ли MSB единицей, которая не может быть единицей, потому что она была просто обнулена (0x80 — это маска, которая обнуляет каждый бит, кроме MSB). Таким образом, он проверяет неправильное значение.
Это правильный образец (источник)
def _ReadVarintHelper(self):
"""Helper for the various varint-reading methods above.
Reads an unsigned, varint-encoded integer from the stream and
returns this integer.
Does no bounds checking except to ensure that we read at most as many bytes
as could possibly be present in a varint-encoded 64-bit number.
"""
result = 0
shift = 0
while 1:
if shift >= 64:
raise message.DecodeError('Too many bytes when decoding varint.')
try:
b = ord(self._buffer[self._pos])
except IndexError:
raise message.DecodeError('Truncated varint.')
self._pos = 1
result |= ((b amp; 0x7f) << shift)
shift = 7
if not (b amp; 0x80):
return result