रीड () और रिकव (), और बिटवीन सेंड () और राइट () के बीच अंतर क्या है?


199

बीच क्या अंतर है read()और recv(), और के बीच send()और write()प्रदर्शन, गति और अन्य व्यवहार के मामले में सॉकेट प्रोग्रामिंग में?


3
इस तरह लागू होने के बारे में सोचें #define write(...) send(##__VA_ARGS__, 0):।
सावधान

जवाबों:


128

अंतर यह है कि recv()/ send()केवल सॉकेट के डिस्क्रिप्टर पर काम करते हैं और आपको वास्तविक ऑपरेशन के लिए कुछ विकल्प निर्दिष्ट करते हैं। वे फ़ंक्शंस थोड़े अधिक विशिष्ट हैं (उदाहरण के लिए, आप अनदेखा करने के लिए SIGPIPE, या बाहर-बाहर संदेश भेजने के लिए एक ध्वज सेट कर सकते हैं ...)।

कार्य read()/ write()हैं सार्वभौमिक फ़ाइल वर्णनकर्ता सभी वर्णनकर्ता पर काम कर काम करता है।


3
यह गलत है, 0 लंबाई के डेटाग्राम के मामले में एक और अंतर है - यदि एक शून्य-लंबाई डेटाग्राम लंबित है, तो पढ़ें (2) और रीव () शून्य के झंडे तर्क के साथ अलग व्यवहार प्रदान करते हैं। इस परिस्थिति में, रीड (2) का कोई प्रभाव नहीं होता (डेटाग्राम लंबित रहता है), जबकि रिकव () लंबित डेटाग्राम का उपभोग करता है।
अभिनव गौनियाल

2
@AbhinavGauniyal अलग व्यवहार कैसे प्रदान करेगा ? यदि कोई 0 बाइट डेटाग्राम है, तो दोनों recvऔर readकॉल करने वाले को कोई डेटा नहीं देगा , लेकिन कोई त्रुटि भी नहीं होगी। कॉलर के लिए, व्यवहार समान है। कॉल करने वाले को डेटाग्राम के बारे में कुछ भी पता नहीं हो सकता है (यह नहीं पता हो सकता है कि यह एक सॉकेट है और फाइल नहीं है, यह नहीं पता हो सकता है कि यह डेटाग्राम सॉकेट है और स्ट्रीम सॉकेट नहीं है)। डेटाग्राम लंबित रहने से यह पता चलता है कि कैसे कर्नेल में आईपी स्टैक काम करता है और कॉलर को दिखाई नहीं देता है। कॉलर के दृष्टिकोण से, वे अभी भी समान व्यवहार प्रदान करेंगे।
मैकी

2
@ मेकी कि हर किसी के लिए ज्ञान का निहितार्थ नहीं है, मुझे उदाहरण के लिए ले लो :)
अभिनव गनियाल

1
@Mecki 0 बाइट्स के गैर-अवरोधक सफल रीड को क्या दर्शाता है? क्या डेटाग्राम अभी भी लंबित है? वास्तव में, और केवल यही, मुझे चिंतित कर रहा है: एक व्यवहार जो डेटाग्राम सफलतापूर्वक पढ़े जाने पर भी लंबित रह सकता है। मुझे यकीन नहीं है कि क्या स्थिति पैदा हो सकती है, जो कि मैं इसे ध्यान में रखना चाहूंगा।
सेह

2
@ यदि आप चिंतित हैं, तो आप उपयोग क्यों नहीं करते recv? पहली जगह में क्यों recvऔर sendकहाँ से परिचय कराया गया था इसका कारण यह था कि सभी डाटाग्राम अवधारणाओं को धाराओं की दुनिया में मैप नहीं किया जा सकता था। readऔर writeडेटा की एक धारा के रूप में सब कुछ समझो, चाहे वह एक पाइप, एक फ़ाइल, एक उपकरण (जैसे एक सीरियल पोर्ट) या एक सॉकेट हो। फिर भी एक सॉकेट केवल एक वास्तविक स्ट्रीम है अगर यह टीसीपी का उपयोग करता है। यदि यह यूडीपी का उपयोग करता है तो यह एक ब्लॉक डिवाइस की तरह है। लेकिन अगर दोनों पक्ष इसे एक धारा की तरह उपयोग करते हैं, तो यह एक धारा की तरह काम करेगा और आप writeकॉल का उपयोग करके खाली यूडीपी पैकेट भी नहीं भेज सकते हैं, इसलिए यह स्थिति उत्पन्न नहीं होगी।
मेकी

85

Google पर पहली हिट के अनुसार

read () recv () के झंडे पैरामीटर के साथ 0. के बराबर है। झंडे पैरामीटर के लिए अन्य मान recv के व्यवहार को बदलते हैं ()। इसी तरह, लिखना () झंडे के साथ (=) 0 भेजने के बराबर है।


31
यह पूरी कहानी नहीं है। recvकेवल सॉकेट पर उपयोग किया जा सकता है, और यदि आप इसे उपयोग करने का प्रयास करते हैं, तो एक त्रुटि उत्पन्न करेगा, कहते हैं STDIN_FILENO
जॉय एडम्स

77
यह धागा अब Google पर पहली हिट है, Google
स्टैकओवरफ्लो से

12

read()और write()अधिक सामान्य हैं, वे किसी भी फाइल डिस्क्रिप्टर के साथ काम करते हैं। हालाँकि, वे Windows पर काम नहीं करेंगे।

आप अतिरिक्त विकल्प पास कर सकते हैं send()और recv()इसलिए, आपको उन्हें कुछ मामलों में उपयोग करना पड़ सकता है।


7

मैंने अभी हाल ही में देखा कि जब मैं write()विंडोज में सॉकेट पर इस्तेमाल करता था, तो यह लगभग काम करता है (एफडी पास write()नहीं हुआ था जैसा कि एक पास किया गया था send(), मैं _open_osfhandle()एफडी पास करने के लिए प्राप्त करता था write())। हालाँकि, यह काम नहीं किया जब मैंने द्विआधारी डेटा भेजने की कोशिश की जिसमें वर्ण 10. शामिल write()था। इसे send()0 के झंडे पैरामीटर के साथ बदलना उस समस्या को ठीक करता है। read()13-10 बाइनरी डेटा में लगातार होने पर रिवर्स समस्या हो सकती है, लेकिन मैंने इसका परीक्षण नहीं किया है। लेकिन उस के बीच एक और संभव अंतर प्रतीत होता है send()और write()



6

लिनक्स पर एक और बात है:

sendगैर-सॉकेट fd पर काम करने की अनुमति नहीं देता है। इस प्रकार, उदाहरण के लिए यूएसबी पोर्ट पर लिखना writeआवश्यक है।


2

"प्रदर्शन और गति"? उन प्रकार के नहीं हैं ... समानार्थक शब्द, यहाँ?

वैसे भी, recv()कॉल उन झंडों को लेता है read(), जो इसे और अधिक शक्तिशाली या कम से कम सुविधाजनक नहीं बनाता है। वह एक अंतर है। मुझे नहीं लगता कि कोई महत्वपूर्ण प्रदर्शन अंतर है, लेकिन इसके लिए परीक्षण नहीं किया है।


15
शायद झंडे से निपटने के लिए अधिक सुविधाजनक नहीं माना जा सकता है।
सेमाज

2

लिनक्स पर मैंने यह भी देखा कि:

सिग्नल हैंडलर द्वारा सिस्टम कॉल और लाइब्रेरी फ़ंक्शंस में रुकावट
यदि सिस्टम कॉल या लाइब्रेरी फ़ंक्शन कॉल को सिग्नल हैंडलर लागू किया जाता है, तो या तो:

  • सिग्नल हैंडलर के वापस आने के बाद कॉल स्वतः रीस्टार्ट हो जाती है; या

  • कॉल त्रुटि EINTR के साथ विफल हो जाती है।

... विवरण UNIX प्रणालियों में भिन्न होता है; नीचे, लिनक्स के लिए विवरण।

यदि निम्न में से किसी एक इंटरफेस को अवरुद्ध कॉल सिग्नल हैंडलर द्वारा बाधित किया जाता है, तो SA_RESTART ध्वज का उपयोग किए जाने पर सिग्नल हैंडलर वापस आने के बाद कॉल स्वचालित रूप से फिर से चालू हो जाती है; अन्यथा कॉल EINTR त्रुटि के साथ विफल हो जाती है:

  • read (2), readv (2), write (2), writev (2), और ioctl (2) कॉल "धीमे" उपकरणों पर।

.....

SA_RESTART के उपयोग की परवाह किए बिना सिग्नल हैंडलर द्वारा बाधित होने के बाद निम्नलिखित इंटरफेस को कभी भी पुनरारंभ नहीं किया जाता है; सिग्नल हैंडलर द्वारा बाधित होने पर वे हमेशा त्रुटि EINTR के साथ विफल होते हैं:

  • "इनपुट" सॉकेट इंटरफेस, जब एक टाइमआउट (SO_RCVTIMEO) setsockopt (2) का उपयोग कर सॉकेट पर सेट कर दिया गया है: (2) स्वीकार करते हैं, recv (2), recvfrom (2) recvmmsg (2) भी एक गैर शून्य के साथ, ( समयबाह्य तर्क), और पुनरावृत्ति (2)।

  • "आउटपुट" सॉकेट इंटरफेस, जब सेटआउट (2): कनेक्ट (2), सेंड (2), सेंडटो (2), और सेंडग (2) का उपयोग करके सॉकेट पर एक टाइमआउट (SO_RCVTIMEO) सेट किया गया है।

man 7 signalअधिक जानकारी के लिए जाँच करें ।


recvfromअनिश्चित काल तक अवरुद्ध रहने से बचने के लिए एक सरल उपयोग सिग्नल का उपयोग करेगा ।

APUE का एक उदाहरण :

#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h>

#define BUFLEN      128
#define TIMEOUT     20

void
sigalrm(int signo)
{
}

void
print_uptime(int sockfd, struct addrinfo *aip)
{
    int     n;
    char    buf[BUFLEN];

    buf[0] = 0;
    if (sendto(sockfd, buf, 1, 0, aip->ai_addr, aip->ai_addrlen) < 0)
        err_sys("sendto error");
    alarm(TIMEOUT);
    //here
    if ((n = recvfrom(sockfd, buf, BUFLEN, 0, NULL, NULL)) < 0) {
        if (errno != EINTR)
            alarm(0);
        err_sys("recv error");
    }
    alarm(0);
    write(STDOUT_FILENO, buf, n);
}

int
main(int argc, char *argv[])
{
    struct addrinfo     *ailist, *aip;
    struct addrinfo     hint;
    int                 sockfd, err;
    struct sigaction    sa;

    if (argc != 2)
        err_quit("usage: ruptime hostname");
    sa.sa_handler = sigalrm;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGALRM, &sa, NULL) < 0)
        err_sys("sigaction error");
    memset(&hint, 0, sizeof(hint));
    hint.ai_socktype = SOCK_DGRAM;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;
    if ((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)
        err_quit("getaddrinfo error: %s", gai_strerror(err));

    for (aip = ailist; aip != NULL; aip = aip->ai_next) {
        if ((sockfd = socket(aip->ai_family, SOCK_DGRAM, 0)) < 0) {
            err = errno;
        } else {
            print_uptime(sockfd, aip);
            exit(0);
        }
    }

    fprintf(stderr, "can't contact %s: %s\n", argv[1], strerror(err));
    exit(1);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.