बीच क्या अंतर है read()
और recv()
, और के बीच send()
और write()
प्रदर्शन, गति और अन्य व्यवहार के मामले में सॉकेट प्रोग्रामिंग में?
बीच क्या अंतर है read()
और recv()
, और के बीच send()
और write()
प्रदर्शन, गति और अन्य व्यवहार के मामले में सॉकेट प्रोग्रामिंग में?
जवाबों:
अंतर यह है कि recv()
/ send()
केवल सॉकेट के डिस्क्रिप्टर पर काम करते हैं और आपको वास्तविक ऑपरेशन के लिए कुछ विकल्प निर्दिष्ट करते हैं। वे फ़ंक्शंस थोड़े अधिक विशिष्ट हैं (उदाहरण के लिए, आप अनदेखा करने के लिए SIGPIPE
, या बाहर-बाहर संदेश भेजने के लिए एक ध्वज सेट कर सकते हैं ...)।
कार्य read()
/ write()
हैं सार्वभौमिक फ़ाइल वर्णनकर्ता सभी वर्णनकर्ता पर काम कर काम करता है।
recv
और read
कॉल करने वाले को कोई डेटा नहीं देगा , लेकिन कोई त्रुटि भी नहीं होगी। कॉलर के लिए, व्यवहार समान है। कॉल करने वाले को डेटाग्राम के बारे में कुछ भी पता नहीं हो सकता है (यह नहीं पता हो सकता है कि यह एक सॉकेट है और फाइल नहीं है, यह नहीं पता हो सकता है कि यह डेटाग्राम सॉकेट है और स्ट्रीम सॉकेट नहीं है)। डेटाग्राम लंबित रहने से यह पता चलता है कि कैसे कर्नेल में आईपी स्टैक काम करता है और कॉलर को दिखाई नहीं देता है। कॉलर के दृष्टिकोण से, वे अभी भी समान व्यवहार प्रदान करेंगे।
recv
? पहली जगह में क्यों recv
और send
कहाँ से परिचय कराया गया था इसका कारण यह था कि सभी डाटाग्राम अवधारणाओं को धाराओं की दुनिया में मैप नहीं किया जा सकता था। read
और write
डेटा की एक धारा के रूप में सब कुछ समझो, चाहे वह एक पाइप, एक फ़ाइल, एक उपकरण (जैसे एक सीरियल पोर्ट) या एक सॉकेट हो। फिर भी एक सॉकेट केवल एक वास्तविक स्ट्रीम है अगर यह टीसीपी का उपयोग करता है। यदि यह यूडीपी का उपयोग करता है तो यह एक ब्लॉक डिवाइस की तरह है। लेकिन अगर दोनों पक्ष इसे एक धारा की तरह उपयोग करते हैं, तो यह एक धारा की तरह काम करेगा और आप write
कॉल का उपयोग करके खाली यूडीपी पैकेट भी नहीं भेज सकते हैं, इसलिए यह स्थिति उत्पन्न नहीं होगी।
Google पर पहली हिट के अनुसार
read () recv () के झंडे पैरामीटर के साथ 0. के बराबर है। झंडे पैरामीटर के लिए अन्य मान recv के व्यवहार को बदलते हैं ()। इसी तरह, लिखना () झंडे के साथ (=) 0 भेजने के बराबर है।
recv
केवल सॉकेट पर उपयोग किया जा सकता है, और यदि आप इसे उपयोग करने का प्रयास करते हैं, तो एक त्रुटि उत्पन्न करेगा, कहते हैं STDIN_FILENO
।
read()
और write()
अधिक सामान्य हैं, वे किसी भी फाइल डिस्क्रिप्टर के साथ काम करते हैं। हालाँकि, वे Windows पर काम नहीं करेंगे।
आप अतिरिक्त विकल्प पास कर सकते हैं send()
और recv()
इसलिए, आपको उन्हें कुछ मामलों में उपयोग करना पड़ सकता है।
मैंने अभी हाल ही में देखा कि जब मैं write()
विंडोज में सॉकेट पर इस्तेमाल करता था, तो यह लगभग काम करता है (एफडी पास write()
नहीं हुआ था जैसा कि एक पास किया गया था send()
, मैं _open_osfhandle()
एफडी पास करने के लिए प्राप्त करता था write()
)। हालाँकि, यह काम नहीं किया जब मैंने द्विआधारी डेटा भेजने की कोशिश की जिसमें वर्ण 10. शामिल write()
था। इसे send()
0 के झंडे पैरामीटर के साथ बदलना उस समस्या को ठीक करता है। read()
13-10 बाइनरी डेटा में लगातार होने पर रिवर्स समस्या हो सकती है, लेकिन मैंने इसका परीक्षण नहीं किया है। लेकिन उस के बीच एक और संभव अंतर प्रतीत होता है send()
और write()
।
लिनक्स पर एक और बात है:
send
गैर-सॉकेट fd पर काम करने की अनुमति नहीं देता है। इस प्रकार, उदाहरण के लिए यूएसबी पोर्ट पर लिखना write
आवश्यक है।
"प्रदर्शन और गति"? उन प्रकार के नहीं हैं ... समानार्थक शब्द, यहाँ?
वैसे भी, recv()
कॉल उन झंडों को लेता है read()
, जो इसे और अधिक शक्तिशाली या कम से कम सुविधाजनक नहीं बनाता है। वह एक अंतर है। मुझे नहीं लगता कि कोई महत्वपूर्ण प्रदर्शन अंतर है, लेकिन इसके लिए परीक्षण नहीं किया है।
लिनक्स पर मैंने यह भी देखा कि:
सिग्नल हैंडलर द्वारा सिस्टम कॉल और लाइब्रेरी फ़ंक्शंस में रुकावट
यदि सिस्टम कॉल या लाइब्रेरी फ़ंक्शन कॉल को सिग्नल हैंडलर लागू किया जाता है, तो या तो:
सिग्नल हैंडलर के वापस आने के बाद कॉल स्वतः रीस्टार्ट हो जाती है; या
कॉल त्रुटि 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);
}
#define write(...) send(##__VA_ARGS__, 0)
:।