2013-11-03 36 views
5

我需要从C/C++的linux套接字中读取VarInts。任何图书馆,想法或什么?从linux套接字读取“varint”

我尝试阅读和铸造焦炭为bool [8]尝试没有成功读取VarInt ...

而且,这是一个新的Minecraft 1.7.2通信协议兼容性,因此,也the documentation of the protocol可能帮帮我。

让我解释一下我的项目:我正在制作一个Minecraft服务器软件来运行在我的VPS中(因为java太慢了......),并且我被这个协议困住了。一个线程等待连接,当它有一个新连接时,它创建一个新的Client对象并启动开始与客户端通信的客户端线程。

我认为没有必要显示代码。如果我错了,告诉我,我会用一些代码编辑。

+2

我以前从来没见过varints,但我想谷歌的“varint C库”,并得到了一些打击。 –

回答

11

首先,请注意varints作为实际字节发送,而不是字符10的字符串。

对于一个无符号的varint,我相信下面的代码会为你解码,假设你已经在data指向的缓冲区中获得了varint数据。该示例函数返回参考参数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,您可以使用调用第一第二个功能:

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; 
} 

要编码varints,可以使用以下函数。请注意,缓冲区uint8_t *const data应该至少有10个字节的空间,因为最大的varint长度为10个字节。
的#include

// 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); 
} 
+1

感谢那个巨大的答案。也许我是脱离主题,但是,我如何编码?我想我应该看看位操作符... – azteca1998

+1

编码类似于解码。我将掀起一对编码功能并将它们扔到那里。 –

+0

再次感谢!我不需要保留10个字节,因为我正在修改函数来发送构建的varint。该函数将从循环的每一步向客户端发送1个字节。 – azteca1998