यह रिपोर्ट करता है कि यह लौटने के लिए तैयार है।
select
आमतौर पर आपके प्रोग्राम के नियंत्रण से बाहर होने वाली घटनाओं की प्रतीक्षा करता है। संक्षेप में, select
पर कॉल करके, आपका प्रोग्राम कहता है "मेरे पास तब तक कुछ नहीं है ..., कृपया मेरी प्रक्रिया को निलंबित करें"।
आपके द्वारा निर्दिष्ट शर्त घटनाओं का एक सेट है, जिसमें से कोई भी आपको जगाएगा।
उदाहरण के लिए, यदि आप कुछ डाउनलोड कर रहे हैं, तो आपके लूप को आने के लिए नए डेटा पर इंतजार करना होगा, स्थानांतरण होने पर एक टाइमआउट होना होगा, या उपयोगकर्ता को बाधा डालना होगा, जो ठीक है select
करता है।
जब आपके पास एकाधिक डाउनलोड होते हैं, तो आपके किसी भी कनेक्शन पर आने वाले डेटा आपके प्रोग्राम में गतिविधि को ट्रिगर करते हैं (आपको डिस्क पर डेटा लिखना होगा), ताकि आप select
पर सभी डाउनलोड कनेक्शन की सूची दे सकें "पढ़ने" के लिए देखने के लिए फ़ाइल डिस्क्रिप्टर फ़ाइल करें।
जब आप एक ही समय में कहीं भी डेटा अपलोड करते हैं, तो यह देखने के लिए कि कनेक्शन वर्तमान में डेटा स्वीकार करता है या नहीं, आप फिर से select
का उपयोग करते हैं। यदि दूसरी तरफ डायलअप पर है, तो यह केवल डेटा को धीरे-धीरे स्वीकार करेगा, इसलिए आपका स्थानीय प्रेषण बफर हमेशा भरा रहता है, और अधिक डेटा लिखने का कोई भी प्रयास तब तक अवरुद्ध होगा जब तक बफर स्पेस उपलब्ध न हो या असफल हो। फ़ाइल डिस्क्रिप्टर को पास करके हम select
पर "लिखने" वर्णनकर्ता के रूप में भेज रहे हैं, जैसे ही बफर स्पेस भेजने के लिए हमें सूचित किया जाता है।
सामान्य विचार यह है कि आपका प्रोग्राम ईवेंट संचालित बन जाता है, यानी यह अनुक्रमिक संचालन करने के बजाए एक सामान्य संदेश पाश से बाह्य घटनाओं पर प्रतिक्रिया करता है। आप कर्नेल को बताते हैं "यह उन घटनाओं का सेट है जिसके लिए मैं कुछ करना चाहता हूं", और कर्नेल आपको घटनाओं का एक सेट देता है जो हुआ है। एक साथ होने वाली दो घटनाओं के लिए यह काफी आम है; उदाहरण के लिए, एक डेटा पैकेट में एक टीसीपी स्वीकृति शामिल की गई थी, यह वही एफडी दोनों पठनीय (डेटा उपलब्ध है) और लिखने योग्य (स्वीकृत डेटा को प्रेषक बफर से हटा दिया गया है) बना सकता है, इसलिए आपको सभी घटनाओं को संभालने के लिए तैयार रहना चाहिए select
को दोबारा कॉल करने से पहले।
बारीकियों से एक है कि select
मूल रूप से आप एक वादा है कि read
या write
में से एक मंगलाचरण ब्लॉक नहीं, कॉल खुद के बारे में कोई गारंटी किए बिना देता है।उदाहरण के लिए, यदि बफर स्पेस का एक बाइट उपलब्ध है, तो आप 10 बाइट्स लिखने का प्रयास कर सकते हैं, और कर्नेल वापस आ जाएगा और कहेंगे "मैंने 1 बाइट लिखा है", इसलिए आपको इस मामले को संभालने के लिए भी तैयार रहना चाहिए। एक सामान्य दृष्टिकोण एक बफर "डेटा को इस एफडी में लिखा जाना है", और जब तक यह खाली नहीं है, एफडी को लिखने के सेट में जोड़ा जाता है, और "लिखने योग्य" घटना को सभी लिखने का प्रयास करके संभाला जाता है वर्तमान में बफर में डेटा। यदि बफर बाद में खाली है, तो ठीक है, अगर नहीं, तो बस "लिखने योग्य" पर प्रतीक्षा करें।
"असाधारण" सेट का शायद ही कभी उपयोग किया जाता है - इसका उपयोग उन प्रोटोकॉल के लिए किया जाता है, जिनमें डेटा के हस्तांतरण के लिए संभव है, जबकि डेटा को स्थानांतरित करने के लिए संभव है, जबकि अन्य डेटा को पार करने की आवश्यकता है। यदि आपका प्रोग्राम वर्तमान में "पठनीय" फ़ाइल डिस्क्रिप्टर से डेटा स्वीकार नहीं कर सकता है (उदाहरण के लिए, आप डाउनलोड कर रहे हैं, और डिस्क भर चुकी है), तो आप "पठनीय" सेट में वर्णक शामिल नहीं करना चाहते हैं, क्योंकि आप ईवेंट को संभाल नहीं सकते और select
तत्काल वापस आने पर वापस आ जाएगा। यदि रिसीवर में "असाधारण" सेट में एफडी शामिल है, और प्रेषक अपने आईपी स्टैक को "तत्काल" डेटा के साथ एक पैकेट भेजने के लिए कहता है, तो रिसीवर तब जागृत हो जाता है, और अनचाहे डेटा को त्यागने और प्रेषक के साथ पुन: सिंक्रनाइज़ करने का निर्णय ले सकता है । telnet
प्रोटोकॉल इसका उपयोग करता है, उदाहरण के लिए, Ctrl-C हैंडलिंग के लिए। जब तक आप ऐसे प्रोटोकॉल को डिज़ाइन नहीं कर रहे हैं जिसके लिए ऐसी सुविधा की आवश्यकता होती है, तो आप आसानी से इसे बिना किसी नुकसान के बाहर छोड़ सकते हैं।
अनिवार्य कोड उदाहरण:
#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>
#include <stdbool.h>
static inline int max(int lhs, int rhs) {
if(lhs > rhs)
return lhs;
else
return rhs;
}
void copy(int from, int to) {
char buffer[10];
int readp = 0;
int writep = 0;
bool eof = false;
for(;;) {
fd_set readfds, writefds;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
int ravail, wavail;
if(readp < writep) {
ravail = writep - readp - 1;
wavail = sizeof buffer - writep;
}
else {
ravail = sizeof buffer - readp;
wavail = readp - writep;
}
if(!eof && ravail)
FD_SET(from, &readfds);
if(wavail)
FD_SET(to, &writefds);
else if(eof)
break;
int rc = select(max(from,to)+1, &readfds, &writefds, NULL, NULL);
if(rc == -1)
break;
if(FD_ISSET(from, &readfds))
{
ssize_t nread = read(from, &buffer[readp], ravail);
if(nread < 1)
eof = true;
readp = readp + nread;
}
if(FD_ISSET(to, &writefds))
{
ssize_t nwritten = write(to, &buffer[writep], wavail);
if(nwritten < 1)
break;
writep = writep + nwritten;
}
if(readp == sizeof buffer && writep != 0)
readp = 0;
if(writep == sizeof buffer)
writep = 0;
}
}
हम हम बफर स्थान उपलब्ध है और कोई अंत फ़ाइल या पढ़ा तरफ त्रुटि थी, और हम अगर हम डेटा है लिखने के लिए प्रयास करता है, तो पढ़ने के लिए प्रयास बफर में; अगर अंत-फ़ाइल तक पहुंचा है और बफर खाली है, तो हम कर रहे हैं।
यह कोड स्पष्ट रूप से उपरोक्त (यह उदाहरण कोड है) व्यवहार करेगा, लेकिन आपको यह देखने में सक्षम होना चाहिए कि कर्नेल के लिए पढ़ने और लिखने दोनों के लिए पूछे जाने वाले कर्नेल के लिए यह स्वीकार्य है, इस मामले में हम अभी वापस जाते हैं और कहें "जब भी आप तैयार हों", और यह पूछे बिना कि हम इसे अवरुद्ध करेंगे या नहीं।
http://beej.us/guide/bgnet/output/html/multipage/selectman.html –
@ निकोलई एनफेटिसोव - आपके लिंक से, 'चयन() रिटर्न के बाद, सेट में मान दिखाए जाएंगे पढ़ने या लिखने के लिए तैयार हैं, और जिनके पास अपवाद हैं। 'तो' चयन() 'की वापसी के कारण हमें बताया गया कि सॉकेट पढ़ने के लिए तैयार है? यही कारण है कि मुझे – Mike
समझ में नहीं आता है जब इन-कर्नेल नेटवर्क स्टैक का पता लगाता है कि किसी भी सॉकेट डिस्क्रिप्टर पर लंबित कोई ईवेंट है, तो आपकी प्रक्रिया प्रतीक्षा से और 'चयन' रिटर्न से जागृत हो जाती है। एफडी सेट इन-आउट पैरामीटर हैं - आप कर्नेल को बताते हैं कि आप किसमें रुचि रखते हैं, यह आपको बताता है कि क्या हुआ। –