2013-11-03 3 views
5

आई/सी C++ में linux सॉकेट से एक VarInts पढ़ने की जरूरत है। कोई पुस्तकालय, विचार या कुछ?पढ़ें linux सॉकेट से "varint"

मैं पढ़ और कास्टिंग चार [8] सफलता एक VarInt पढ़ने के लिए बिना कोशिश करने के लिए bool करने की कोशिश की ...

इसके अलावा, इस नए Minecraft 1.7.2 संचार प्रोटोकॉल के साथ संगतता के लिए है, इसलिए, the documentation of the protocol भी कर सकते हैं मदद।

मेरे प्रोजेक्ट के बारे में बताएं: मैं अपने VPS में चलाने के लिए एक Minecraft सर्वर सॉफ्टवेयर बना रही हूँ (क्योंकि जावा बहुत धीमी है ...) और मैं प्रोटोकॉल के साथ अटक गई। एक धागा कनेक्शन के लिए इंतजार कर रहा है और जब यह एक नया संबंध नहीं है, यह एक नई ग्राहक वस्तु बनाता है और ग्राहक धागा है कि ग्राहक के साथ संवाद स्थापित शुरू होता है शुरू होता है।

मुझे लगता है कि कोड को दिखाने के लिए कोई जरूरत नहीं है कि। यदि मैं गलत हूं, तो मुझे बताएं और मैं कुछ कोड के साथ संपादित करूंगा।

+2

मैं पहले कभी नहीं देखा varints, लेकिन मैं "varint ग पुस्तकालय" के लिए गूगल की कोशिश की और कुछ हिट हो गया। –

उत्तर

11

सबसे पहले, ध्यान दें कि varin वास्तविक बाइट्स के रूप में भेजे जाते हैं, वर्णों के तार 1 और 0 नहीं।

एक हस्ताक्षरित वैरिंट के लिए, मेरा मानना ​​है कि निम्नलिखित आपके लिए इसे डीकोड करेगा, मान लें कि आपको 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 के रूप में सबसे बड़ा varint 10 बाइट्स लंबा है, कम से कम 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); 
} 
+1

उस विशाल उत्तर के लिए धन्यवाद। शायद मैं ऑफ-विषय हूं लेकिन, मैं इसे कैसे एन्कोड कर सकता हूं? मुझे लगता है कि मुझे थोड़ा ऑपरेटर देखना चाहिए ... – azteca1998

+1

एनकोड डीकोड के समान है। मैं एन्कोड कार्यों की एक जोड़ी को चाबुक करूंगा और उन्हें वहां फेंक दूंगा। –

+0

फिर से धन्यवाद! मुझे 10 बाइट्स आरक्षित करने की कोई आवश्यकता नहीं है क्योंकि मैं वर्ंट को इसके निर्माण के रूप में भेजने के लिए फ़ंक्शन का अनुकूलन कर रहा हूं। फ़ंक्शन लूप से प्रत्येक चरण क्लाइंट को 1 बाइट भेज देगा। – azteca1998