गैर-अवरुद्ध सॉकेट पर एपोल के साथ एसिंक सॉकेट आईओ करते समय, पढ़ना सीधा लगता है: बस epoll_wait जब तक सॉकेट पढ़ने के लिए तैयार न हो, और तब तक पढ़ें जब तक आपको EAGAIN/EWOULDBLOCK न मिल जाए।

लेकिन आप कैसे भेजते हैं? संभवत: एक भी बड़ा send ऑपरेशन करने से ब्लॉक हो जाएगा, इसलिए आपको हमेशा EAGAIN/EWOULDBLOCK मिलेगा। आप क्या करने वाले हैं?

0
CaptainCodeman 22 अक्टूबर 2020, 21:48

2 जवाब

सबसे बढ़िया उत्तर

संभवतः कर्नेल सभी डेटा तुरंत नहीं भेज पाएगा, इसलिए send सफलता पर भेजे गए बाइट्स की संख्या लौटाता है। महत्वपूर्ण बात यह है कि लौटाई गई संख्या कॉल में निर्दिष्ट कुल लंबाई से कम कर सकती है (और सबसे अधिक संभावना होगी)। आपको उत्तर के रूप में केवल EAGAIN/EWOULDBLOCK मिलेगा यदि बिल्कुल कोई बाइट नहीं भेजा जा सकता है। इसलिए बड़ी मात्रा में डेटा भेजते समय, आपको केवल (बहुत संभावना) संभावना को सही ढंग से संभालने की आवश्यकता होती है कि सभी डेटा एक बार में नहीं भेजे जाते हैं।

नोट: यह डेटाग्राम (UDP) सॉकेट के लिए अलग है, क्योंकि आंशिक डेटाग्राम नहीं भेजे जा सकते। अधिक जानकारी के लिए POSIX: UDP सॉकेट पर राइट () से रिटर्न वैल्यू देखें।

यहाँ एक SOCK_STREAM (TCP) सॉकेट मानकर एक उदाहरण दिया गया है:

size_t len;
size_t sent;
char *buf;

/* ... prepare data ... */

while (sent < len) {
    ssize_t n;

    if ((n = send(sockfd, buf + sent, len - sent, flags)) == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            continue;
        } else {
            perror("send failed");
            exit(1);
        }
    }
    
    sent += n;
}
4
Marco Bonelli 25 अक्टूबर 2020, 16:52

send/to() जितने बाइट भेज सकता है, भेजेगा, यह लौटाएगा कि यह वास्तव में कितने बाइट भेजने में सक्षम था।

यदि आप TCP सॉकेट का उपयोग कर रहे हैं, तो send() को लूप में तब तक कॉल करें जब तक कि आपके सभी बाइट भेज नहीं दिए जाते या EAGAIN/EWOULDBLOCK की सूचना नहीं मिल जाती। बाद के मामले में, लूप को रोकें और शेष बाइट्स को कहीं कैश करें।

यदि आप UDP सॉकेट का उपयोग कर रहे हैं, तो send/to() केवल संपूर्ण डेटाग्राम भेज सकता है, इसलिए लूप का उपयोग बिल्कुल भी न करें, और यदि EAGAIN/EWOULDBLOCK की रिपोर्ट की जाती है, तो संपूर्ण डेटाग्राम को कैश करें।

जब भी epoll इंगित करता है कि सॉकेट लिखने योग्य है, तो उस सॉकेट के लिए कोई भी कैश्ड बाइट्स/डेटाग्राम आवश्यकतानुसार भेजें, कैश से केवल सफल बाइट्स/डेटाग्राम को हटा दें, जब तक कि कैश साफ़ न हो जाए या EAGAIN/EWOULDBLOCK बताया जाता है। कैश में न भेजे गए बाइट/डेटाग्राम छोड़ दें।

जब भी आपको नए टीसीपी बाइट्स, या एक नया यूडीपी डेटाग्राम भेजने की आवश्यकता होती है, यदि सॉकेट का कैश खाली नहीं है, तो बाइट्स/डेटाग्राम को कैश के अंत में संलग्न करें और आगे बढ़ें, अन्यथा बाइट्स/डेटाग्राम को तुरंत भेजने का प्रयास करें, कैशिंग यदि जैसा कि ऊपर बताया गया है, EAGAIN/EWOULDBLOCK की रिपोर्ट की गई है।

3
Remy Lebeau 23 अक्टूबर 2020, 01:31