दिलचस्प पोस्ट
जब गतिविधि / टुकड़ा रोका गया है, तब हैंडलर संदेशों को कैसे संभालना है एसक्यूलाइट निकटतम स्थान प्राप्त करना (अक्षांश और देशांतर के साथ) मैं रिमोट जीआईटी शाखा कैसे बदलूंगा? सी अल्पविराम ऑपरेटर आदिम मूल्य बनाम संदर्भ मूल्य रूबी, एक्सेल, सिस्टम और% x () या बैकटीक्स के बीच का अंतर स्विफ्ट 2 में हटाए गए .toInt ()? जावा लुक एंड फेल (एल एंड एफ) पायथन में @staticmethod और @classmethod के बीच अंतर क्या है? स्ट्रिंग का मूल्यांकन "3 * (4 + 2)" उपज 18 ASP.NET MVC: यूनिट परीक्षण नियंत्रक जो UrlHelper का उपयोग करते हैं OAuth 2 से OAuth 2 अलग कैसे है? SQL सर्वर के लिए LIMIT और OFFSET के समतुल्य? शेर के तहत रूबी के साथ आरवीएम – जीसीसी मुद्दों को स्थापित नहीं किया जा सकता है मैं एक बटन जैसा एक HTML लिंक कैसे बना सकता हूं?

Protobuf-net का उपयोग करते हुए, मुझे अचानक अज्ञात तार-प्रकार के बारे में एक अपवाद मिला

(यह एक ऐसे प्रश्न का फिर से पोस्ट होता है जिसे मैंने अपने आरएसएस में देखा था, लेकिन ओ.पी. द्वारा हटा दिया गया था। मैंने इसे फिर से जोड़ दिया है क्योंकि मैंने देखा है कि इस प्रश्न को कई जगहों से कई बार पूछा गया है "विकी के लिए" अच्छा प्रपत्र")

अचानक, मुझे deserializing और संदेश है जब एक ProtoException प्राप्त होता है: अज्ञात तार-प्रकार 6

  • तार प्रकार क्या है?
  • अलग-अलग तार-प्रकार के मूल्य और उनके विवरण क्या हैं?
  • मुझे संदेह है कि एक क्षेत्र समस्या पैदा कर रहा है, इसे कैसे डिबग करें?

वेब के समाधान से एकत्रित समाधान "Protobuf-net का उपयोग करते हुए, मुझे अचानक अज्ञात तार-प्रकार के बारे में एक अपवाद मिला"

जांच करने वाली पहली बात:

INPUT डेटा प्रोटीब्यू डेटा क्या है? यदि आप किसी अन्य स्वरूप (जेसन, एक्सएमएल, सीएसवी, बाइनरी-फॉर्मेटर) की कोशिश करते हैं या पार्स करते हैं, उदाहरण के लिए, या बस टूटी हुई डेटा (एक "आंतरिक सर्वर त्रुटि" HTML प्लेसहोल्डर पाठ पृष्ठ), तो यह काम नहीं करेगा


तार प्रकार क्या है?

यह एक 3-बिट ध्वज है जो इसे बताता है (विस्तृत शब्दों में, यह केवल 3 बिट्स के बाद है) अगले डेटा क्या दिखता है

प्रोटोकॉल बफ़र्स में प्रत्येक फ़ील्ड एक हेडर द्वारा प्रीफ़िक्स्ड है जो यह बताता है कि यह किस फील्ड (संख्या) को दर्शाता है, और किस प्रकार का डेटा अगले समय आ रहा है; इस "किस प्रकार के डेटा" को उस मामले का समर्थन करने के लिए जरूरी है जहां अप्रत्याशित डेटा स्ट्रीम में है (उदाहरण के लिए, आपने डेटा को एक छोर पर फ़ील्ड जोड़ा है), क्योंकि इससे सीरियललाइजर को यह पता चलता है कि पिछली कैसे पढ़ें डेटा (या यदि आवश्यक हो तो राउंड ट्रिप के लिए इसे स्टोर करें)

अलग-अलग तार-प्रकार के मूल्य और उनके विवरण क्या हैं?

  • 0: भिन्नता-लंबाई पूर्णांक (64 बिट तक) – बेस -122 एमएसबी संकेत जारी रखने के साथ एन्कोडेड (पूर्णांक प्रकारों के लिए डिफ़ॉल्ट के रूप में इस्तेमाल किया गया है, जिसमें एंमों सहित)
  • 1: 64-बिट – डेटा के 8 बाइट्स ( double लिए उपयोग किया जाता है, या long / ulong लिए वैकल्पिक )
  • 2: लंबाई-प्रीफ़िक्स्ड – पहले वेरिएंट लंबाई एन्कोडिंग का उपयोग करते हुए एक पूर्णांक पढ़ा; यह आपको बताता है कि डेटा के कितने बाइट्स का पालन करें (स्ट्रिंग्स, byte[] , "पैक किए गए" एरेज़ के लिए और बाल ऑब्जेक्ट गुण / सूचियों के लिए डिफ़ॉल्ट के लिए उपयोग किया गया है)
  • 3: "समूह शुरू करें" – प्रारंभिक / अंत टैग का उपयोग करने वाली चाइल्ड ऑब्जेक्ट एन्कोडिंग के लिए एक वैकल्पिक तंत्र – जो बड़े पैमाने पर Google द्वारा नापसंद है, यह पूरे बच्चे-ऑब्जेक्ट फ़ील्ड को छोड़ने के लिए अधिक महंगा है क्योंकि आप केवल एक अनपेक्षित वस्तु
  • 4: "अंत समूह" – 3 के साथ जुड़वां
  • 5: 32-बिट – डेटा के 4 बाइट्स ( float लिए उपयोग किया जाता है, या int / uint और अन्य छोटे पूर्णांक प्रकारों के लिए वैकल्पिक )

मुझे संदेह है कि एक क्षेत्र समस्या पैदा कर रहा है, इसे कैसे डिबग करें?

क्या आप एक फ़ाइल में धारावाहिक हैं? सबसे अधिक संभावना (मेरे अनुभव में) यह है कि आपने एक मौजूदा फ़ाइल को ओवरराइट किया है, लेकिन इसे कम नहीं किया है; यानी यह 200 बाइट्स था ; आपने इसे फिर से लिखा है, लेकिन केवल 182 बाइट्स के साथ। अब आपकी स्ट्रीम के अंत में कचरे के 18 बाइट्स हैं जो इसे ट्रिपट कर रहे हैं प्रोटोकॉल बफर पुन: लिखने के दौरान फ़ाइलों को छोटा करना चाहिए आप इसे FileMode साथ कर सकते हैं:

 using(var file = new FileStream(path, FileMode.Truncate)) { // write } 

या वैकल्पिक रूप से SetLength द्वारा अपना डेटा लिखने के बाद :

 file.SetLength(file.Position); 

अन्य संभावित कारण

आप (गलती से) किसी धारा को धारावाहिक रूप से भिन्न प्रकार से अलग करना चाहते हैं। यह सुनिश्चित नहीं हो रहा है कि यह संभव नहीं है।

चूंकि स्टैक ट्रेस इस स्टैक ओव्हरफ्लो प्रश्न का संदर्भ देता है, इसलिए मैंने सोचा कि मैं बताता हूं कि आप इस अपवाद को भी प्राप्त कर सकते हैं यदि आप (गलती से) किसी धारा को धारावाहिक के मुकाबले एक अलग प्रकार के रूप में अलग करना चाहते हैं। इसलिए यह सुनिश्चित करने के लिए कि यह नहीं हो रहा है, वार्तालाप के दोनों पक्षों को दोहरे जांच कर रहा है।

यह भी एक से अधिक प्रोटोकु संदेश एक ही स्ट्रीम में लिखने के प्रयास के कारण हो सकता है। इसका समाधान सीरियलाइज विथ लाईनपेपिक्स और डिसेराइलाइज विथ लाईनपेफिक्स का उपयोग करना है।


ऐसा क्यूँ होता है:

प्रोटोकुफ विनिर्देश तार प्रकारों (बाइनरी स्टोरेज स्वरूप) और डेटा-प्रकार (.नेट आदि डेटा-प्रकार) की काफी छोटी संख्या का समर्थन करता है। इसके अतिरिक्त, यह 1: 1 नहीं है, न ही 1 है: बहुत से या बहुत से: 1- एक वायर-टाइप का उपयोग कई डेटा-प्रकारों के लिए किया जा सकता है, और एक डेटा-प्रकार को किसी भी वायर-प्रकारों के माध्यम से एन्कोड किया जा सकता है । एक परिणाम के रूप में, आप पूरी तरह से एक प्रोटॉबफ टुकड़ा को नहीं समझ सकते हैं जब तक कि आप पहले से ही scema को जानते नहीं हैं, ताकि आपको पता हो कि प्रत्येक मान को कैसे व्याख्या किया जाए। जब आप कहें, तो एक Int32 डेटा-प्रकार पढ़ना, समर्थित तार-प्रकार "varint", "fixed32" और "fixed64" हो सकते हैं, जहां-जहां String डाटा-प्रकार पढ़ते हैं, केवल समर्थित तार-प्रकार है "स्ट्रिंग"।

यदि डेटा-प्रकार और वायर-प्रकार के बीच कोई संगत मानचित्र नहीं है, तो डेटा को पढ़ा नहीं जा सकता है, और यह त्रुटि उठाई गई है।

अब देखते हैं कि यहां परिदृश्य में ऐसा क्यों होता है:

 [ProtoContract] public class Data1 { [ProtoMember(1, IsRequired=true)] public int A { get; set; } } [ProtoContract] public class Data2 { [ProtoMember(1, IsRequired = true)] public string B { get; set; } } class Program { static void Main(string[] args) { var d1 = new Data1 { A = 1}; var d2 = new Data2 { B = "Hello" }; var ms = new MemoryStream(); Serializer.Serialize(ms, d1); Serializer.Serialize(ms, d2); ms.Position = 0; var d3 = Serializer.Deserialize<Data1>(ms); // This will fail var d4 = Serializer.Deserialize<Data2>(ms); Console.WriteLine("{0} {1}", d3, d4); } } 

उपरोक्त में, दो संदेश प्रत्येक-दूसरे के बाद सीधे लिखे जाते हैं जटिलता यह है कि: प्रोटॉबफ एक अनुलग्न प्रारूप है, जिसका अर्थ है "मर्ज"। एक प्रोटोकु संदेश को अपनी लंबाई नहीं पता है , इसलिए संदेश पढ़ने का डिफ़ॉल्ट तरीका है: EOF तक पढ़ें। हालांकि, यहां हमने दो भिन्न प्रकारों को जोड़ा है अगर हम इसे वापस पढ़ते हैं, तो यह नहीं पता कि जब हमने पहला संदेश पढ़ना समाप्त कर दिया है, तो यह पढ़ना जारी रखता है। जब दूसरे संदेश से डेटा प्राप्त होता है, तो हम स्वयं को "स्ट्रिंग" वायर-प्रकार पढ़ते हैं, लेकिन हम अभी भी एक डेटा 1 इंस्टेंस को आबाद करने की कोशिश कर रहे हैं, जिसके लिए सदस्य 1 Int32 "स्ट्रिंग" और Int32 बीच कोई नक्शा नहीं है, इसलिए यह विस्फोट हो जाता है।

*WithLengthPrefix विधियों serializer को यह जानने की अनुमति देता है कि प्रत्येक संदेश कब खत्म हो जाता है; इसलिए, यदि हम *WithLengthPrefix का उपयोग करते हुए डेटा 1 और डेटा 2 को *WithLengthPrefix करते हैं, तो *WithLengthPrefix विधियों का उपयोग करते हुए एक Data2 और एक Data2 को *WithLengthPrefix , फिर यह दो उदाहरणों के बीच आने वाले डेटा को ठीक से विभाजित करता है, केवल सही ऑब्जेक्ट में सही मान पढ़ रहा है।

इसके अतिरिक्त, जब इस तरह के विषम डेटा को संग्रहीत किया जाता है, तो आप अतिरिक्त कक्षा (प्रत्येक के साथ एक अलग फ़ील्ड-नंबर *WithLengthPrefix ) को आवंटित करना चाहेंगे; यह किस प्रकार की उच्च दृश्यता को deserialized किया जा रहा है Serializer.NonGeneric में भी एक विधि है, जो तब डेटा को deserialize करने के लिए इस्तेमाल किया जा सकता है बिना अग्रिम में जानने के लिए जो हम deserializing हैं :

 // Data1 is "1", Data2 is "2" Serializer.SerializeWithLengthPrefix(ms, d1, PrefixStyle.Base128, 1); Serializer.SerializeWithLengthPrefix(ms, d2, PrefixStyle.Base128, 2); ms.Position = 0; var lookup = new Dictionary<int,Type> { {1, typeof(Data1)}, {2,typeof(Data2)}}; object obj; while (Serializer.NonGeneric.TryDeserializeWithLengthPrefix(ms, PrefixStyle.Base128, fieldNum => lookup[fieldNum], out obj)) { Console.WriteLine(obj); // writes Data1 on the first iteration, // and Data2 on the second iteration } 

पिछली उत्तर पहले से ही समस्या की तुलना में बेहतर बता सकते हैं। मैं अपवाद को पुन: उत्पन्न करने के लिए एक आसान तरीका भी जोड़ना चाहता हूं।

यह त्रुटि भी तब भी हो सकती है, जब एक serialized ProtoMember प्रकार deserialization के दौरान अपेक्षित प्रकार से भिन्न होता है।

उदाहरण के लिए यदि क्लाइंट निम्न संदेश भेजता है:

 public class DummyRequest { [ProtoMember(1)] public int Foo{ get; set; } } 

लेकिन जो संदेश संदेश को deserializes में निम्न वर्ग है:

 public class DummyRequest { [ProtoMember(1)] public string Foo{ get; set; } } 

उसके बाद इस मामले में थोड़ा गुमराह करने वाला त्रुटि संदेश होगा

ProtoBuf.ProtoException: अवैध वायर-प्रकार; इसका आम तौर पर मतलब है कि आपने फ़ाइल को छांटने या लंबाई निर्धारित करने के बिना फ़ाइल को ओवर-लिखित किया है

यह तब भी घटित होगा यदि संपत्ति का नाम परिवर्तित हो। मान लीजिए कि क्लाइंट ने इसके बजाय निम्नलिखित भेजा है:

 public class DummyRequest { [ProtoMember(1)] public int Bar{ get; set; } } 

यह अभी भी सर्वर को int Bar को string Foo करने के लिए ProtoBuf.ProtoException कारण ProtoBuf.ProtoException जो उसी ProtoBuf.ProtoException कारण बनता है।

मुझे उम्मीद है कि यह किसी को अपने आवेदन को डीबग करने में सहायता करता है।

यह भी स्पष्ट करें कि आपके सभी उपवर्गों में [ProtoContract] विशेषता है कभी-कभी आप यह याद कर सकते हैं जब आपके पास अमीर डीटीओ है

यदि आप SerializeWithLengthPrefix का उपयोग कर रहे हैं, तो कृपया ध्यान दें कि object का ProtoBuf.ProtoException : Invalid wire-type करने के लिए object प्रकार deserialization कोड को तोड़ता है और ProtoBuf.ProtoException : Invalid wire-type कारण बनता है ProtoBuf.ProtoException : Invalid wire-type

 using (var ms = new MemoryStream()) { var msg = new Message(); Serializer.SerializeWithLengthPrefix(ms, (object)msg, PrefixStyle.Base128); // Casting msg to object breaks the deserialization code. ms.Position = 0; Serializer.DeserializeWithLengthPrefix<Message>(ms, PrefixStyle.Base128) } 

मैंने इस समस्या को देखा है जब बाइट्स को स्ट्रिंग्स में और बाहर कन्वर्ट करने के लिए अनुचित Encoding प्रकार का उपयोग करते हुए।

Encoding.Default का उपयोग करने की आवश्यकता है। Encoding.Default और नहीं Encoding.UTF8 . Encoding.UTF8

 using (var ms = new MemoryStream()) { Serializer.Serialize(ms, obj); var bytes = ms.ToArray(); str = Encoding.Default.GetString(bytes); }