মধ্যে পার্থক্য কি read()
এবং recv()
এবং তাদের মধ্যবর্তী send()
এবং write()
পারফরমেন্স, গতি এবং অন্যান্য ব্যবহার পরিপ্রেক্ষিতে সকেট প্রোগ্রামিং?
মধ্যে পার্থক্য কি read()
এবং recv()
এবং তাদের মধ্যবর্তী send()
এবং write()
পারফরমেন্স, গতি এবং অন্যান্য ব্যবহার পরিপ্রেক্ষিতে সকেট প্রোগ্রামিং?
উত্তর:
পার্থক্যটি হ'ল recv()
/ send()
কেবল সকেট বর্ণনাকারীর উপর কাজ করে এবং আপনাকে প্রকৃত ক্রিয়াকলাপের জন্য নির্দিষ্ট বিকল্পগুলি নির্দিষ্ট করতে দেয়। এই ফাংশনগুলি কিছুটা বেশি বিশেষায়িত (উদাহরণস্বরূপ, আপনি অগ্রাহ্য করার জন্য SIGPIPE
, বা ব্যান্ড-আউট-ব্যান্ড বার্তা প্রেরণে একটি পতাকা সেট করতে পারেন ...)।
কার্যাবলী read()
/ write()
হয় সার্বজনীন ফাইল বর্ণনাকারী সব বর্ণনাকারী কাজ ফাংশন।
recv
এবং read
কলারের কাছে কোনও ডেটা সরবরাহ করবে না তবে ত্রুটিও নেই। কলারের জন্য, আচরণটি একই রকম। কলকারী এমনকি ডেটাগ্রাম সম্পর্কে কিছু জানেন না (এটি জানেন না যে এটি একটি সকেট এবং কোনও ফাইল নয়, এটি জানেন না যে এটি কোনও ডেটাগ্রামের সকেট এবং স্ট্রিম সকেট নয়)। ডেটাগ্রামে মুলতুবি থাকার বিষয়টি হ'ল আইপি স্ট্যাকগুলি কার্নেলগুলিতে কীভাবে কাজ করে এবং কলারের কাছে দৃশ্যমান নয় সে সম্পর্কে অন্তর্নিহিত জ্ঞান। কলারের দৃষ্টিকোণ থেকে তারা এখনও সমান আচরণ করবে।
recv
? প্রথম স্থানটিতে কেন recv
এবং send
কোথায় প্রবর্তন করা হয়েছিল তা হ'ল সমস্ত ডেটাগ্রাম ধারণাগুলি স্রোতের জগতে ম্যাপ করা যায় না। read
এবং write
তথ্য একটি স্ট্রিম, তা একটি নল, একটি ফাইল, একটি ডিভাইস (যেমন একটি সিরিয়াল পোর্ট) অথবা একটি সকেট হিসাবে আচরণ সবকিছু। তবুও কোনও সকেট কেবল আসল স্ট্রিম যদি এটি টিসিপি ব্যবহার করে। যদি এটি ইউডিপি ব্যবহার করে তবে এটি একটি ব্লক ডিভাইসের মতো। তবে উভয় পক্ষ যদি এটি স্ট্রিমের মতো ব্যবহার করে তবে এটি স্রোতের মতো কাজ করবে এবং আপনি write
কল ব্যবহার করে খালি ইউডিপি প্যাকেটটি পাঠাতেও পারবেন না , সুতরাং এই পরিস্থিতি তৈরি হবে না।
গুগলে প্রথম হিট প্রতি
পঠন () 0 এর পতাকা প্যারামিটার সহ recv () এর সমতুল্য, পতাকাগুলির প্যারামিটারের জন্য অন্যান্য মানগুলি rec () এর আচরণ পরিবর্তন করে। একইভাবে, লিখুন () পতাকাগুলি == 0 পাঠানোর সমতুল্য।
recv
কেবলমাত্র সকেটে ব্যবহার করা যেতে পারে এবং আপনি যদি এটি ব্যবহার করার চেষ্টা করেন, বলুন, ত্রুটি তৈরি করবে STDIN_FILENO
।
read()
এবং write()
আরও জেনেরিক, তারা কোনও ফাইল বর্ণনাকারীর সাথে কাজ করে। তবে তারা উইন্ডোজে কাজ করবে না।
আপনি অতিরিক্ত বিকল্পগুলি পাস করতে পারেন send()
এবং recv()
তাই আপনাকে কিছু ক্ষেত্রে এগুলি ব্যবহার করতে হতে পারে।
আমি সম্প্রতি লক্ষ্য করেছি যে আমি যখন write()
উইন্ডোজের সকেটে ব্যবহার করতাম , তখন এটি প্রায় কাজ করে (এফডিটি পাসের মতো write()
হয় না send()
; আমি _open_osfhandle()
এফডি পাস করার জন্য ব্যবহার করতাম write()
)। যাইহোক, আমি যখন বাইনারি ডেটা প্রেরণের চেষ্টা করছিলাম তখন এটি কার্যকর হয়নি 10 অক্ষর অন্তর্ভুক্ত write()
যেখানে কোথাও এর আগে 13 টি অক্ষর characterোকানো হয়েছিল। send()
0 এর ফ্ল্যাগ প্যারামিটার দিয়ে এটিকে পরিবর্তন করা সমস্যার সমাধান করে। read()
বাইনারি ডেটাতে 13-10 ধারাবাহিকভাবে থাকলে বিপরীত সমস্যা হতে পারে তবে আমি এটি পরীক্ষা করিনি। তবে এটি send()
এবং এর মধ্যে আরেকটি সম্ভাব্য পার্থক্য বলে মনে হয় write()
।
লিনাক্সের আরেকটি জিনিস হ'ল:
send
নন-সকেট এফডি চালানোর অনুমতি দেয় না। সুতরাং, উদাহরণস্বরূপ ইউএসবি পোর্টে লিখতে, write
প্রয়োজনীয় is
"পারফরম্যান্স এবং গতি"? এখানে কি এই জাতীয় শব্দ নয়?
যাইহোক, recv()
কলটি এমন পতাকা নেয় read()
যা তা দেয় না, এটি এটিকে আরও শক্তিশালী বা কমপক্ষে আরও সুবিধাজনক করে তোলে। এটি একটি পার্থক্য। আমি মনে করি না পার্শ্ববর্তী পারফরম্যান্সের একটি উল্লেখযোগ্য পার্থক্য রয়েছে, তবে এটির জন্য পরীক্ষা করা হয়নি।
লিনাক্সে আমি এটিও লক্ষ্য করেছি:
সিগন্যাল হ্যান্ডলারদের দ্বারা সিস্টেম কল এবং লাইব্রেরি ফাংশনগুলিতে বাধা
যদি কোনও সিস্টেম কল বা লাইব্রেরি ফাংশন কলটি অবরুদ্ধ অবস্থায় একটি সিগন্যাল হ্যান্ডলার আহ্বান করা হয়, তবে হয়:
সিগন্যাল হ্যান্ডলার ফিরে আসার পরে কলটি স্বয়ংক্রিয়ভাবে পুনরায় শুরু হয়; অথবা
EINTR ত্রুটির সাথে কলটি ব্যর্থ হয়।
... বিস্তারিত ইউনিক্স সিস্টেম জুড়ে বিভিন্ন; নীচে, লিনাক্সের জন্য বিশদ।
যদি নিম্নলিখিত কোনও ইন্টারফেসে একটি অবরুদ্ধ কল যদি একটি সিগন্যাল হ্যান্ডলার দ্বারা বাধা দেয়, তবে SA_RESTART পতাকা ব্যবহার করা হলে সিগন্যাল হ্যান্ডলারটি ফিরে আসার পরে কলটি স্বয়ংক্রিয়ভাবে পুনরায় শুরু হয়; অন্যথায় কলটি ত্রুটি EINTR এর সাথে ব্যর্থ হয়:
- পড়া (2), readv (2), লেখ (2), writev (2), ও ioctl (2) "ধীর" ডিভাইসের কল।
.....
সিএআলএসএলএসটিআরটির ব্যবহার ব্যতীত নিম্নলিখিত ইন্টারফেসগুলি সিগন্যাল হ্যান্ডলার দ্বারা বাধা দেওয়ার পরে পুনরায় আরম্ভ করা হবে না; সিগন্যাল হ্যান্ডলার দ্বারা বাধা দেওয়া হলে তারা সর্বদা ত্রুটি EINTR নিয়ে ব্যর্থ হয়:
"ইনপুট" সকেট ইন্টারফেসগুলি যখন সকেটে সেটসকোপ্ট (2) ব্যবহার করে টাইমআউট (SO_RCVTIMEO) সেট করা থাকে: গ্রহণ করুন (2), recv (2), recvfrom (2), recvmmsg (2) (একটি নন-নুলের সাথেও সময়সীমা আর্গুমেন্ট), এবং recvmsg (2)।
"আউটপুট" সকেট ইন্টারফেসগুলি যখন সকেটে সেটসকোপ্ট (2) ব্যবহার করে সকেটে একটি টাইমআউট (SO_RCVTIMEO) সেট করা থাকে: সংযোগ (2), প্রেরণ (2), সেন্ডো (2), এবং সেন্ডসএমজি (2)।
man 7 signal
আরও বিশদ জন্য পরীক্ষা করুন।
recvfrom
অনির্দিষ্টকালের জন্য অবরুদ্ধ হওয়া এড়াতে একটি সাধারণ ব্যবহার হ'ল ব্যবহারের সংকেত ।
এপিইউ থেকে একটি উদাহরণ :
#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)
।