5

C/C++ で Linux ソケットからVarIntを読み取る必要があります。ライブラリ、アイデアなどはありますか?

char を読み取って bool[8] にキャストしようとしましたが、VarInt を読み取ることができませんでした...

また、これは新しい Minecraft 1.7.2 通信プロトコルとの互換性のためのものであるため、プロトコルのドキュメントも役立つ場合があります。

私のプロジェクトを説明させてください: VPS で実行する Minecraft サーバー ソフトウェアを作成しています (java が遅すぎるため...)、プロトコルに行き詰まりました。1 つのスレッドが接続を待機し、新しい接続があると、新しい Client オブジェクトを作成し、クライアントとの通信を開始する Client スレッドを開始します。

コードを示す必要はないと思います。私が間違っている場合は教えてください。いくつかのコードで編集します。

4

1 に答える 1

13

まず、varint は、文字列10.

署名されていない varint の場合、 が指すバッファーに varint データがあると仮定すると、次のようにデコードされると思いますdata。このサンプル関数は、参照引数でデコードされたバイト数を返しますint decoded_bytes

uint64_t decode_unsigned_varint( const uint8_t *const data, int &decoded_bytes )
{
    int i = 0;
    uint64_t decoded_value = 0;
    int shift_amount = 0;

    do 
    {
        decoded_value |= (uint64_t)(data[i] & 0x7F) << shift_amount;     
        shift_amount += 7;
    } while ( (data[i++] & 0x80) != 0 );

    decoded_bytes = i;
    return decoded_value;
}

署名された varint をデコードするには、最初の関数を呼び出す次の 2 番目の関数を使用できます。

int64_t decode_signed_varint( const uint8_t *const data, int &decoded_bytes )
{
    uint64_t unsigned_value = decode_unsigned_varint(data, decoded_bytes);
    return (int64_t)( unsigned_value & 1 ? ~(unsigned_value >> 1) 
                                         :  (unsigned_value >> 1) );
}

これらの機能はどちらも正しいと思います。Google ページからいくつかのデータポイントを確認するために、以下のコードを使用していくつかの基本的なテストを行いました。出力は正しいです。

#include <stdint.h>
#include <iostream>


uint64_t decode_unsigned_varint( const uint8_t *const data, int &decoded_bytes )
{
    int i = 0;
    uint64_t decoded_value = 0;
    int shift_amount = 0;

    do 
    {
        decoded_value |= (uint64_t)(data[i] & 0x7F) << shift_amount;     
        shift_amount += 7;
    } while ( (data[i++] & 0x80) != 0 );

    decoded_bytes = i;
    return decoded_value;
}

int64_t decode_signed_varint( const uint8_t *const data, int &decoded_bytes )
{
    uint64_t unsigned_value = decode_unsigned_varint(data, decoded_bytes);
    return (int64_t)( unsigned_value & 1 ? ~(unsigned_value >> 1) 
                                         :  (unsigned_value >> 1) );
}



uint8_t ex_p300[] = { 0xAC, 0x02 };
uint8_t ex_n1  [] = { 0x01 };

using namespace std;

int main()
{
    int decoded_bytes_p300;
    uint64_t p300;

    p300 = decode_unsigned_varint( ex_p300, decoded_bytes_p300 );

    int decoded_bytes_n1;
    int64_t  n1;

    n1 = decode_signed_varint( ex_n1, decoded_bytes_n1 );

    cout << "p300 = " << p300 
         << "   decoded_bytes_p300 = " << decoded_bytes_p300 << endl;

    cout << "n1 = " << n1 
         << "   decoded_bytes_n1 = " << decoded_bytes_n1 << endl;

    return 0;
}

varint をエンコードするには、次の関数を使用できます。最大の varint の長さは 10 バイトであるため、バッファuint8_t *const dataには少なくとも 10 バイトの余裕が必要であることに注意してください。
#含む

// Encode an unsigned 64-bit varint.  Returns number of encoded bytes.
// 'buffer' must have room for up to 10 bytes.
int encode_unsigned_varint(uint8_t *const buffer, uint64_t value)
{
    int encoded = 0;

    do
    {
        uint8_t next_byte = value & 0x7F;
        value >>= 7;

        if (value)
            next_byte |= 0x80;

        buffer[encoded++] = next_byte;

    } while (value);


    return encoded;
}

// Encode a signed 64-bit varint.  Works by first zig-zag transforming
// signed value into an unsigned value, and then reusing the unsigned
// encoder.  'buffer' must have room for up to 10 bytes.
int encode_signed_varint(uint8_t *const buffer, int64_t value)
{
    uint64_t uvalue;

    uvalue = uint64_t( value < 0 ? ~(value << 1) : (value << 1) );

    return encode_unsigned_varint( buffer, uvalue );
}
于 2013-11-04T01:11:49.860 に答える