2013-11-03 2 views
5

나는 C/C++의 리눅스 소켓에서 VarInts을 읽을 필요가있다. 어떤 도서관, 아이디어 또는 무엇인가?리눅스 소켓에서 "varint"읽기

또한,이 새로운 마인 크래프트 1.7.2 통신 프로토콜과의 호환성을위한

내가 읽고 [8]는 VarInt을 읽을 수있는 성공없이 시도 BOOL 사용하는 문자를 캐스팅하려고

... 그래서, the documentation of the protocol도 할 수있다 도움.

내 프로젝트를 설명해 주겠다 : 내 VPS에서 실행되는 Minecraft 서버 소프트웨어를 만들고있다. (자바가 너무 느리기 때문에 ...) 나는 프로토콜을 고수했다. 한 스레드는 연결을 기다리고 새 연결이있을 때 새 Client 객체를 만들고 클라이언트와의 통신을 시작하는 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; 
} 

varint를 인코딩하려면 다음 기능을 사용할 수 있습니다. 버퍼 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