आंशिक रीड पर यूनिक्स स्ट्रीम सहायक डेटा के साथ क्या होता है?


18

इसलिए मैंने यूनिक्स-स्ट्रीम सहायक डेटा के बारे में बहुत सारी जानकारी पढ़ी है, लेकिन सभी दस्तावेज़ों से एक चीज़ गायब है जब एक आंशिक रीड हो तो क्या होना चाहिए?

मान लीजिए कि मैं 24 बाइट बफर में निम्नलिखित संदेश प्राप्त कर रहा हूं

msg1 [20 byes]   (no ancillary data)
msg2 [7 bytes]   (2 file descriptors)
msg3 [7 bytes]   (1 file descriptor)
msg4 [10 bytes]  (no ancillary data)
msg5 [7 bytes]   (5 file descriptors)

पहले कॉल करने के लिए, मुझे msg1 (और msg2 का हिस्सा? क्या ओएस कभी ऐसा करेगा?) अगर मुझे msg2 का हिस्सा मिलता है, तो क्या मुझे तुरंत डेटा मिल जाएगा, और इसे अगले पढ़ने के लिए सहेजने की आवश्यकता है। जब मुझे पता है कि संदेश वास्तव में मुझे डेटा के साथ क्या करने के लिए कह रहा था? यदि मैं msg1 से 20 बाइट्स मुक्त करता हूं और फिर से कॉल करता हूं, तो क्या वह कभी भी msg3 और msg4 को एक ही समय पर वितरित करेगा? क्या संदेश 3 और msg4 से सहायक डेटा नियंत्रण संदेश संरचना में संक्षिप्त हो जाता है?

जब मैं परीक्षण कार्यक्रमों को प्रयोगात्मक रूप से यह पता लगाने के लिए लिख सकता था, तो मैं प्रलेखन के बारे में देख रहा हूं कि सहायक डेटा स्ट्रीमिंग संदर्भ में कैसे व्यवहार करता है। यह अजीब लगता है कि मुझे इस पर कुछ भी आधिकारिक नहीं मिल रहा है।


मैं अपने प्रायोगिक निष्कर्ष यहाँ जोड़ने जा रहा हूँ, जो मुझे इस परीक्षण कार्यक्रम से मिला:

https://github.com/nrdvana/daemonproxy/blob/master/src/ancillary_test.c

लिनक्स 3.2.59, 3.17.6

ऐसा प्रतीत होता है कि लिनक्स अन्य संदेशों के अंत में सहायक-असर वाले संदेशों के कुछ हिस्सों को जोड़ देगा, जब तक कि इस कॉल के दौरान पुनरावृत्ति के लिए कोई पूर्व सहायक पेलोड देने की आवश्यकता न हो। एक बार एक संदेश के सहायक डेटा को वितरित किया जा रहा है, यह अगले सहायक डेटा संदेश को शुरू करने के बजाय एक छोटी रीडिंग लौटाएगा। इसलिए, ऊपर दिए गए उदाहरण में, मुझे जो लिखा हुआ मिलता है वह है:

recv1: [24 bytes] (msg1 + partial msg2 with msg2's 2 file descriptors)
recv2: [10 bytes] (remainder of msg2 + msg3 with msg3's 1 file descriptor)
recv3: [17 bytes] (msg4 + msg5 with msg5's 5 file descriptors)
recv4: [0 bytes]

बीएसडी 4.4, 10.0

बीएसडी लिनक्स की तुलना में अधिक संरेखण प्रदान करता है, और सहायक डेटा के साथ एक संदेश की शुरुआत से तुरंत पहले एक छोटी रीडिंग देता है । लेकिन, यह खुशी से एक सहायक-असर संदेश के अंत में एक गैर-सहायक-असर संदेश को जोड़ देगा। तो बीएसडी के लिए, ऐसा लगता है कि यदि आपका बफर सहायक-असर वाले संदेश से बड़ा है, तो आपको लगभग पैकेट जैसा व्यवहार मिलता है। मेरे द्वारा पढ़ी जाने वाली पुस्तकें हैं:

recv1: [20 bytes] (msg1)
recv2: [7 bytes]  (msg2, with msg2's 2 file descriptors)
recv3: [17 bytes] (msg3, and msg4, with msg3's 1 file descriptor)
recv4: [7 bytes]  (msg5 with 5 file descriptors)
recv5: [0 bytes]

करने के लिए:

अभी भी जानना चाहेंगे कि पुराने लिनक्स, आईओएस, सोलारिस, आदि पर यह कैसे होता है और भविष्य में ऐसा कैसे हो सकता है।


स्ट्रीम और पैकेट को भ्रमित न करें, एक स्ट्रीम में कोई गारंटी नहीं है कि डेटा उसी चंक्स में वितरित किया जाएगा जो इसे भेजा गया था, इसके लिए आपको एक पैकेट आधारित प्रोटोकॉल की आवश्यकता होगी, न कि स्ट्रीम आधारित।
ctrl-alt-delor 20

ठीक यही कारण है कि मैं यह सवाल पूछ रहा हूँ
एम कॉनराड

आदेश को संरक्षित किया जाना चाहिए। यही धाराएँ करती हैं। यदि एक अवरुद्ध रीडिंग 0 देता है, तो यह स्ट्रीम का अंत है। यदि यह एक और संख्या देता है तो अधिक हो सकता है, आपको यह पता लगाने के लिए कम से कम एक और पढ़ना होगा। संदेश 1, संदेश 2 आदि जैसी कोई चीज नहीं है। आपको इसे अपने प्रोटोकॉल में जोड़ना है, यदि आपको इसकी आवश्यकता है।
ctrl-alt-delor

1
विशेष रूप से, मेरे पास एक पाठ-स्ट्रीम प्रोटोकॉल है और मैं एक कमांड जोड़ रहा हूं जो एक फाइल डिस्क्रिप्टर को पाठ की एक पंक्ति के साथ पास करता है। मुझे यह जानना आवश्यक है कि कोड को ठीक से लिखने के लिए संदेश के पाठ के संबंध में यह सहायक डेटा किस क्रम में प्राप्त हुआ है।
एम कॉनराड

1
@ परिषद: मैं POSIX.1g विनिर्देशन की एक प्रति प्राप्त करने का प्रयास करूंगा। यदि यह स्पष्ट रूप से वहां नहीं लिखा गया है, तो आप कार्यान्वयन-विशिष्ट व्यवहार की अपेक्षा कर सकते हैं।
लास्ज़्लो वल्को

जवाबों:


1

सहायक डेटा प्राप्त होता है जैसे कि इसे खंड (यदि कोई हो) में पहले सामान्य डेटा ऑक्टेट के साथ कतारबद्ध किया गया था।

- POSIX.1-2017

आपके प्रश्न के बाकी हिस्सों के लिए, चीजें थोड़ी बालों वाली होती हैं।

... इस खंड के प्रयोजनों के लिए, एक डेटाग्राम को एक डेटा खंड माना जाता है जो एक रिकॉर्ड को समाप्त करता है, और जिसमें एक विशेष प्रकार के सहायक डेटा के रूप में एक स्रोत पता शामिल होता है।

डेटा खंड को कतार में रखा जाता है क्योंकि प्रोटोकॉल द्वारा डेटा को सॉकेट में दिया जाता है। सामान्य डेटा खंड कतार के अंत में रखे जाते हैं क्योंकि वे वितरित किए जाते हैं। यदि एक नए खंड में पूर्ववर्ती खंड के समान डेटा शामिल है और इसमें कोई सहायक डेटा शामिल नहीं है, और यदि पूर्ववर्ती खंड रिकॉर्ड को समाप्त नहीं करता है, तो खंड तार्किक रूप से एक एकल खंड में विलय हो जाते हैं ...

एक प्राप्त संचालन कभी भी एक से अधिक खंड से डेटा या सहायक डेटा वापस नहीं करेगा।

इसलिए आधुनिक बीएसडी सॉकेट इस एक्सट्रैक्ट से बिल्कुल मेल खाते हैं। यह आश्चर्य की बात नहीं है :-)।

याद रखें कि PIXIX मानक UNIX के बाद, और BSD बनाम सिस्टम V की तरह विभाजन के बाद लिखा गया था। एक मुख्य लक्ष्य व्यवहार की मौजूदा सीमा को समझने में मदद करना था, और मौजूदा विशेषताओं में और भी अधिक विभाजन को रोकना था।

लिनक्स बीएसडी कोड के संदर्भ के बिना लागू किया गया था। यह यहां अलग तरह से व्यवहार करता प्रतीत होता है।

  1. अगर मैं आपको सही तरीके से पढ़ता हूं, तो ऐसा लगता है कि जब लिनक्स एक नए खंड में सहायक डेटा को शामिल करता है, तो इसके अतिरिक्त "सेगमेंट" का विलय होता है , लेकिन पिछले खंड में नहीं है।

  2. आपका कहना है कि "लिनक्स अन्य संदेशों के अंत में सहायक-असर वाले संदेशों के कुछ हिस्सों को संलग्न करेगा, जब तक कि इस कॉल को पुनः प्राप्त करने के लिए किसी पूर्व सहायक पेलोड को वितरित करने की आवश्यकता नहीं है", मानक द्वारा पूरी तरह से समझाया नहीं गया है। एक संभावित स्पष्टीकरण में एक दौड़ की स्थिति शामिल होगी। यदि आप "सेगमेंट" का हिस्सा पढ़ते हैं, तो आपको सहायक डेटा प्राप्त होगा। शायद लिनक्स ने इसकी व्याख्या की जिसका अर्थ है कि शेष खंड अब सहायक डेटा सहित मायने नहीं रखता है! इसलिए जब एक नया खंड प्राप्त होता है, तो इसे विलय कर दिया जाता है - या तो मानक के अनुसार, या अंतर 1 के अनुसार।

यदि आप एक अधिकतम पोर्टेबल कार्यक्रम लिखना चाहते हैं, तो आपको इस क्षेत्र से पूरी तरह से बचना चाहिए। सहायक डेटा का उपयोग करते समय, डेटाग्राम सॉकेट का उपयोग करना अधिक सामान्य है । यदि आप उन सभी अजीब प्लेटफार्मों पर काम करना चाहते हैं जो तकनीकी रूप से ज्यादातर POSIX की तरह कुछ प्रदान करने की आकांक्षा रखते हैं, तो आपका प्रश्न एक अंधेरे और अनछुए कोने में पहुंचना प्रतीत होता है।


आप तर्क कर सकते हैं कि लिनक्स अभी भी कई महत्वपूर्ण सिद्धांतों का अनुसरण करता है:

  1. "सहायक डेटा प्राप्त होता है जैसे कि इसे खंड में पहले सामान्य डेटा ऑक्टेट के साथ कतारबद्ध किया गया था"।
  2. सहायक डेटा कभी भी "संक्षिप्त" नहीं होता है, जैसा कि आप इसे डालते हैं।

हालाँकि, मैं आश्वस्त नहीं हूं कि लिनक्स व्यवहार विशेष रूप से उपयोगी है , जब आप इसकी तुलना बीएसडी व्यवहार से करते हैं। ऐसा लगता है कि आपके द्वारा वर्णित प्रोग्राम में लिनक्स-विशिष्ट वर्कअराउंड जोड़ने की आवश्यकता होगी। और मैं नहीं जानता कि क्यों लिनक्स आपसे ऐसा करने की उम्मीद करेगा।

लिनक्स कर्नेल कोड लिखते समय यह समझदार लग सकता है, लेकिन कभी भी किसी भी कार्यक्रम द्वारा परीक्षण या व्यायाम किए बिना।

या इसे कुछ प्रोग्राम कोड द्वारा प्रयोग किया जा सकता है जो ज्यादातर इस सबसेट के तहत काम करता है, लेकिन सिद्धांत रूप में एज-केस "बग" या दौड़ की स्थिति हो सकती है।

यदि आप लिनक्स व्यवहार और इसके इच्छित उपयोग की समझ नहीं बना सकते हैं, तो मुझे लगता है कि यह लिनक्स पर "अंधेरे, अप्रयुक्त कोने" के रूप में व्यवहार करने के लिए तर्क देता है।


गहरी समीक्षा के लिए धन्यवाद! मुझे लगता है कि यहाँ टेकअवे है कि मैं इसे दो बफ़र्स (प्रत्येक डेटा भाग और सहायक भाग के साथ) को सुरक्षित रूप से संभाल सकता हूं; अगर मुझे पहले रीड पर फ़ाइल डिस्क्रिप्टर मिलते हैं और वे मैसेज से संबंधित नहीं हैं, लेकिन एक और मैसेज शुरू होता है, तो अगर अगले रीड में भी एंसिलरी डेटा होता है तो इसका मतलब है कि मैं निश्चित रूप से अपने डेटा मैसेज का अंत पाऊंगा, जो पहली एंसिलरी लोड है। उस दूसरे में पढ़ा। आगे और पीछे की ओर बढ़ते हुए, मुझे हमेशा पहले बाइट के स्थान के आधार पर पेलोड के साथ संदेश का मिलान करने में सक्षम होना चाहिए।
एम कॉनराड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.