UNIX गैर-संपर्क I / O: O_NONBLOCK बनाम FIONBIO


92

बीएसडी सॉकेट प्रोग्रामिंग के संदर्भ में मेरे द्वारा चलाए जाने वाले प्रत्येक उदाहरण और चर्चा में, ऐसा लगता है कि फ़ाइल को डिस्क्रिप्टर I / O मोड पर सेट करने के लिए अनुशंसित तरीका O_NONBLOCKध्वज का उपयोग कर रहा है fcntl(), जैसे

int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

मैं दस वर्षों से UNIX में नेटवर्क प्रोग्रामिंग कर रहा हूं, और हमेशा FIONBIO ioctl()ऐसा करने के लिए कॉल का उपयोग किया है :

int opt = 1;
ioctl(fd, FIONBIO, &opt);

वास्तव में कभी नहीं सोचा क्यों दिया। बस इसे इस तरह सीखा।

क्या किसी एक या दूसरे के संभावित संबंधित गुणों पर कोई टिप्पणी है? मैं कल्पना करता हूं कि पोर्टेबिलिटी लोकोस कुछ हद तक अलग है, लेकिन यह नहीं जानता ioctl_list(2)कि व्यक्तिगत ioctlतरीकों के उस पहलू से किस हद तक बात नहीं की जाती है ।

जवाबों:


134

मानकीकरण करने से पहले ioctl(... FIONBIO... )और fcntl(... O_NDELAY... ), लेकिन ये सिस्टम के बीच असंगत व्यवहार करते थे, और एक ही प्रणाली के भीतर भी। उदाहरण के लिए, FIONBIOसॉकेट्स पर काम करना और O_NDELAYटिट्स पर काम करना आम बात थी , जिसमें पाइप, फीफो और डिवाइस जैसी चीजों के लिए बहुत अधिक असंगतता थी। और अगर आपको नहीं पता था कि आपके पास किस तरह का फाइल डिस्क्रिप्टर है, तो आपको यह सुनिश्चित करने के लिए दोनों सेट करना होगा। लेकिन इसके अलावा, बिना डेटा उपलब्ध न होने वाले रीड को भी असंगत रूप से इंगित किया गया था; OS पर निर्भर करता है और फ़ाइल डिस्क्रिप्टर के प्रकार को पढ़ने के लिए 0, या -1 के साथ इरोजेन, या -1 के साथ इवानो टूलडॉक के साथ वापस आ सकता है। आज भी, सेटिंग FIONBIOयाO_NDELAYसोलारिस पर 0 या टैटी या पाइप पर 0 लौटने के लिए कोई डेटा नहीं है, या सॉकेट पर गलत EAGAIN के साथ -1 का कारण बनता है। हालाँकि, यह अस्पष्ट है क्योंकि यह EOF के लिए भी लौटा है।

POSIX ने इसे पेश करने के साथ संबोधित किया O_NONBLOCK, जिसने विभिन्न प्रणालियों और फ़ाइल डिस्क्रिप्टर प्रकारों में मानकीकृत व्यवहार किया है। क्योंकि मौजूदा सिस्टम आमतौर पर व्यवहार में किसी भी बदलाव से बचना चाहते हैं जो पिछड़ी अनुकूलता को तोड़ सकता है, POSIX ने दूसरों के लिए विशिष्ट व्यवहार को अनिवार्य करने के बजाय एक नया झंडा परिभाषित किया। लिनक्स जैसी कुछ प्रणालियाँ सभी 3 को समान मानती हैं, और EAGAIN और EWOULDBLOCK को भी समान मान से परिभाषित करती हैं, लेकिन पिछड़ी अनुकूलता के लिए कुछ अन्य विरासत व्यवहार को बनाए रखने की इच्छा रखने वाले सिस्टम पुराने तंत्र का उपयोग करने पर ऐसा कर सकते हैं।

नए कार्यक्रमों का उपयोग करना चाहिए fcntl(... O_NONBLOCK... ), के रूप में POSIX द्वारा मानकीकृत।


6
मैं इसके लिए ioctl () का उपयोग करता हूं क्योंकि यह fcntl () के लिए दो के बजाय गैर-अवरोधन मोड को सक्षम करने के लिए मुझे केवल एक ही syscall की लागत देता है। इसके अलावा, विंडोज ioctlsocket () एपीआई इस कार्यक्षमता के प्रयोजनों के लिए ioctl () के बराबर है।
वेज फर्लांग

यदि यह कर सकता है तो nginx ऐसा करता है, और इसे एक टिप्पणी के साथ चिह्नित करता है "ioctl (FIONBIO) एकल syscall के साथ एक गैर-अवरुद्ध मोड सेट करता है।" अब Accept2 है जो आपको एक कनेक्शन स्वीकार करने देता है और इसे उसी syscall में नॉन-ब्लॉकिंग मोड में डालता है।
एलॉफ

6

जैसा कि @ सीन ने कहा, fcntl()बड़े पैमाने पर मानकीकृत है, और इसलिए प्लेटफार्मों भर में उपलब्ध है। ioctl()समारोह से पहले fcntl()यूनिक्स में है, लेकिन सभी पर मानकीकृत नहीं है। यह ioctl()आपके लिए प्रासंगिकता के सभी प्लेटफार्मों पर आपके लिए काम करने का सौभाग्य है, लेकिन इसकी गारंटी नहीं है। विशेष रूप से, दूसरे तर्क के लिए उपयोग किए जाने वाले नाम आर्कन हैं और प्लेटफार्मों के पार विश्वसनीय नहीं हैं। वास्तव में, वे अक्सर विशेष डिवाइस ड्राइवर के लिए अद्वितीय होते हैं जो फ़ाइल डिस्क्रिप्टर संदर्भ। ( ioctl()बीस साल पहले ICX Perq पर चलने वाले PNX (Perq Unix) पर चलने वाले बिट-मैप्ड ग्राफिक्स डिवाइस के लिए उपयोग की जाने वाली कॉल उदाहरण के लिए कभी भी और कहीं भी अनुवादित नहीं की जाती हैं।)


6

मेरा मानना fcntl()है कि POSIX फ़ंक्शन है। जहां ioctl()एक मानक UNIX चीज है। यहाँ POSIX io की एक सूची दी गई है । ioctl()एक बहुत ही कर्नेल / ड्राइवर / OS विशिष्ट चीज़ है, लेकिन मुझे यकीन है कि आप यूनिक्स के अधिकांश स्वादों पर क्या काम करते हैं। कुछ अन्य ioctl()सामान केवल कुछ OS पर काम कर सकते हैं या कुछ निश्चित रीव्स भी कर्नेल के हो सकते हैं।


मैंने AIX, Solaris, Linux, * BSD, और IRIX पर FIONBIO का उपयोग किया है जिसमें कोई समस्या नहीं है। लेकिन हाँ, मैं समझता हूँ कि यह विंडोज पर काम नहीं करने वाला है, उदाहरण के लिए - यह एक बहुत ही विशिष्ट कर्नेल कार्यान्वयन के लिए एक निम्न-स्तरीय इंटरफ़ेस है। फिर भी, मुझे आश्चर्य है कि क्या कोई अन्य विभेदक कारक हैं।
एलेक्स बालाशोव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.