বহনযোগ্যতার দুর্দান্ত জগতে আপনাকে স্বাগতম ... বা বরং এর অভাব রয়েছে। আমরা এই দুটি বিকল্পের বিশদ বিশ্লেষণ করা শুরু করার আগে এবং বিভিন্ন অপারেটিং সিস্টেমগুলি কীভাবে তাদের পরিচালনা করে তা আরও গভীরভাবে দেখার আগে, এটি লক্ষ করা উচিত যে বিএসডি সকেট বাস্তবায়ন সমস্ত সকেট বাস্তবায়নের জননী। মূলত অন্য সমস্ত সিস্টেম বিএসডি সকেট বাস্তবায়নকে কিছু সময় (বা অন্তত এর ইন্টারফেস) অনুলিপি করেছিল এবং তারপরে এটি নিজেরাই বিকশিত হতে শুরু করে। অবশ্যই বিএসডি সকেট বাস্তবায়ন একই সাথে বিবর্তিত হয়েছিল এবং সুতরাং এটির অনুলিপি করা সিস্টেমগুলি পরে এমন বৈশিষ্ট্যগুলি পেয়েছিল যেগুলি এটির আগে অনুলিপি করে এমন সিস্টেমে অভাব ছিল। বিএসডি সকেট বাস্তবায়ন বোঝা অন্য সমস্ত সকেট বাস্তবায়ন বোঝার মূল চাবিকাঠি, সুতরাং আপনার কোনও বিএসডি সিস্টেমের জন্য কোড লেখার জন্য যত্নবান না হওয়া সত্ত্বেও এটি সম্পর্কে পড়া উচিত।
এই দুটি বিকল্পের দিকে নজর দেওয়ার আগে আপনার কয়েকটি বেসিকের জানা উচিত। একটি টিসিপি / ইউডিপি সংযোগটি পাঁচটি মানের দ্বারা চিহ্নিত করা হয়:
{<protocol>, <src addr>, <src port>, <dest addr>, <dest port>}
এই মানগুলির কোনও অনন্য সংমিশ্রণ একটি সংযোগ চিহ্নিত করে। ফলস্বরূপ, কোনও দুটি সংযোগের একই পাঁচটি মান থাকতে পারে না, অন্যথায় সিস্টেম আর এই সংযোগগুলি আলাদা করতে সক্ষম হবে না।
কোনও সকেটের socket()
ক্রিয়াকলাপটি যখন ফাংশন সহ সকেট তৈরি করা হয় তখন সেট করা হয়। উত্স ঠিকানা এবং পোর্ট bind()
ফাংশন দিয়ে সেট করা হয় । গন্তব্য ঠিকানা এবং বন্দর connect()
ফাংশন দিয়ে সেট করা হয় । যেহেতু ইউডিপি একটি সংযোগবিহীন প্রোটোকল, ইউডিপি সকেটগুলি সংযুক্ত না করে ব্যবহার করা যেতে পারে। তবুও এগুলিকে সংযুক্ত করার অনুমতি দেওয়া হয়েছে এবং কিছু ক্ষেত্রে আপনার কোড এবং সাধারণ অ্যাপ্লিকেশন ডিজাইনের জন্য খুব সুবিধাজনক। সংযোগবিহীন মোডে, ইউডিপি সকেটগুলি যখন প্রথমবারের জন্য তাদের উপর ডেটা প্রেরণ করা হয় তখন স্পষ্টভাবে আবদ্ধ হয় না, সাধারণত স্বয়ংক্রিয়ভাবে সিস্টেম দ্বারা আবদ্ধ হয়, কারণ একটি আনবাউন্ড ইউডিপি সকেট কোনও (উত্তর) ডেটা পেতে পারে না। আনবাউন্ড টিসিপি সকেটের ক্ষেত্রেও এটি সত্য, এটি সংযুক্ত হওয়ার আগে এটি স্বয়ংক্রিয়ভাবে আবদ্ধ।
যদি আপনি স্পষ্টভাবে কোনও সকেটকে বেঁধে রাখেন তবে এটি বন্দরে আবদ্ধ হওয়া সম্ভব 0
, যার অর্থ "কোনও বন্দর"। যেহেতু সকেটটি সত্যই বিদ্যমান সমস্ত বন্দরগুলির সাথে আবদ্ধ হতে পারে না, সিস্টেমটিকে সেই ক্ষেত্রে একটি নির্দিষ্ট বন্দর নিজেই বেছে নিতে হবে (সাধারণত পূর্বনির্ধারিত, ওএসের উত্সের বন্দরগুলির নির্দিষ্ট পরিসীমা থেকে)। উত্স ঠিকানার জন্য অনুরূপ ওয়াইল্ডকার্ড বিদ্যমান, যা "কোনও ঠিকানা" হতে পারে ( 0.0.0.0
আইপিভি 4 এর ক্ষেত্রে এবং and::
আইপিভি 6 এর ক্ষেত্রে)। পোর্টগুলির ক্ষেত্রে বিপরীতে, একটি সকেট সত্যই "যে কোনও ঠিকানার" সাথে আবদ্ধ হতে পারে যার অর্থ "সমস্ত স্থানীয় ইন্টারফেসের সমস্ত উত্সের আইপি ঠিকানা"। যদি সকেটটি পরে সংযুক্ত থাকে তবে সিস্টেমটিকে একটি নির্দিষ্ট উত্সের আইপি ঠিকানা চয়ন করতে হবে, যেহেতু একটি সকেট সংযুক্ত করা যায় না এবং একই সাথে কোনও স্থানীয় আইপি ঠিকানার সাথে আবদ্ধ থাকে। গন্তব্য ঠিকানা এবং রাউটিং টেবিলের বিষয়বস্তুর উপর নির্ভর করে, সিস্টেমটি একটি উপযুক্ত উত্স ঠিকানা চয়ন করবে এবং "যে কোনও" বাইন্ডিংকে নির্বাচিত উত্সের আইপি ঠিকানার সাথে বাঁধাইয়ের সাথে প্রতিস্থাপন করবে।
ডিফল্টরূপে, কোনও দুটি সকেট উত্স ঠিকানা এবং উত্স পোর্টের একই সংমিশ্রণে আবদ্ধ হতে পারে না। যতক্ষণ উত্স বন্দরটি পৃথক হয়, উত্সের ঠিকানাটি আসলে অপ্রাসঙ্গিক। বাঁধাই socketA
করার A:X
এবং socketB
করতে B:Y
, যেখানে A
এবং B
ঠিকানাগুলি এবং X
এবং Y
পোর্ট হয়, সবসময় যতদিন সম্ভব X != Y
সত্য। তবে, এমনকি যদি X == Y
, বাধ্যতামূলক এখনও ততক্ষণ সম্ভব যতক্ষণ A != B
সত্য থাকে। যেমন socketA
একটি FTP সার্ভার প্রোগ্রাম জন্যে এবং আবদ্ধ হয় 192.168.0.1:21
এবং socketB
অন্য FTP সার্ভার প্রোগ্রাম জন্যে এবং আবদ্ধ হয় 10.0.0.1:21
, উভয় বাইন্ডিং সফল হবে। মনে রাখবেন, যদিও, কোনও সকেট স্থানীয়ভাবে "কোনও ঠিকানায়" আবদ্ধ হতে পারে। যদি কোনও সকেট আবদ্ধ থাকে0.0.0.0:21
, এটি একই সাথে সমস্ত বিদ্যমান স্থানীয় ঠিকানার সাথে আবদ্ধ এবং সেই ক্ষেত্রে অন্য কোনও সকেট পোর্টে আবদ্ধ হতে পারে 21
না, নির্দিষ্ট আইপি ঠিকানার সাথে এটি নির্ধারিত হওয়ার চেষ্টা করে, এটি 0.0.0.0
বিদ্যমান সমস্ত স্থানীয় আইপি ঠিকানার সাথে দ্বন্দ্ব হিসাবে ।
এখনও অবধি যা কিছু বলা হয়েছে তা সমস্ত বড় অপারেটিং সিস্টেমের জন্য বেশ সমান। ঠিকানার পুনরায় ব্যবহার যখন খেলতে আসে তখন বিষয়গুলি ওএস নির্দিষ্ট হওয়া শুরু করে। আমরা BSD দিয়ে শুরু করি, যেহেতু আমি আগেই বলেছি, এটি সমস্ত সকেট বাস্তবায়নের জননী।
বাসদ
SO_REUSEADDR
যদি SO_REUSEADDR
সকেটে বাঁধানোর আগে এটি সক্ষম করা থাকে তবে উত্সের ঠিকানা এবং পোর্টের ঠিক একই সংমিশ্রণে অন্য সকেটের সাথে বাঁধা না থাকলে সকেটটি সাফল্যের সাথে আবদ্ধ হতে পারে । এখন আপনি ভাবতে পারেন যে এটি আগের চেয়ে আলাদা কীভাবে? মূল শব্দটি "হুবহু"। SO_REUSEADDR
দ্বন্দ্বগুলি অনুসন্ধান করার সময় ওয়াইল্ডকার্ড ঠিকানাগুলি ("কোনও আইপি ঠিকানা") কীভাবে আচরণ করা হয় তা প্রধানত পরিবর্তিত করে।
ছাড়া SO_REUSEADDR
, বাঁধাই socketA
করার 0.0.0.0:21
এবং তারপর বাঁধাই socketB
করার 192.168.0.1:21
(ত্রুটি ব্যর্থ হয়ে যাবে EADDRINUSE
,) যেহেতু 0.0.0.0 মানে হলো "কোনও স্থানীয় IP ঠিকানা", এইভাবে সমস্ত স্থানীয় IP ঠিকানা এই সকেট ব্যবহার করছে বলে মনে করা হয় এবং এই অন্তর্ভুক্ত 192.168.0.1
খুব। সঙ্গে SO_REUSEADDR
এটা সাল থেকে সফল হবে 0.0.0.0
এবং 192.168.0.1
হয় ঠিক একই ঠিকানায়, এক সব স্থানীয় ঠিকানার জন্য একটি ওয়াইল্ড কার্ড এবং অন্যান্য একজন অত্যন্ত সুনির্দিষ্ট স্থানীয় ঠিকানা। নোট করুন যে উপরের বিবৃতিটি যথাযথভাবেই নির্ধারণ করা হয়েছে যা নির্ধারিত socketA
এবং socketB
আবদ্ধ; এটি ছাড়া SO_REUSEADDR
সর্বদা ব্যর্থ হবে, SO_REUSEADDR
এটি সর্বদা সফল হবে।
আপনাকে আরও ভাল ওভারভিউ দেওয়ার জন্য, আসুন এখানে একটি টেবিল তৈরি করুন এবং সমস্ত সম্ভাব্য সংমিশ্রণের তালিকা দিন:
SO_REUSEADDR সকেটএ সকেটবি ফলাফল
-------------------------------------------------- -------------------
চালু / বন্ধ 192.168.0.121 192.168.0.1:21 ত্রুটি (EADDRINUSE)
চালু / বন্ধ 192.168.0.1:21 10.0.0.1:21 ঠিক আছে
অন / অফ 10.0.0.1.121 192.168.0.1:21 ঠিক আছে
বন্ধ 0.0.0.021 192.168.1.0:21 ত্রুটি (EADDRINUSE)
বন্ধ 192.168.1.0:21 0.0.0.0:21 ত্রুটি (EADDRINUSE)
0.0.0.0:21 192.168.1.0:21 ঠিক আছে
192.168.1.0:21 0.0.0.0:21 ঠিক আছে
চালু / বন্ধ 0.0.0.0:21 0.0 0.0.0.0:21 ত্রুটি (EADDRINUSE)
উপরের সারণীটি ধরে নিয়েছে যে socketA
ইতিমধ্যে সফলভাবে প্রদত্ত ঠিকানার সাথে আবদ্ধ হয়েছে socketA
, তারপরে socketB
তৈরি করা হয়, হয় SO_REUSEADDR
সেট হয়ে যায় বা হয় না এবং শেষ পর্যন্ত দেওয়া ঠিকানার সাথে আবদ্ধ থাকে socketB
। Result
জন্য বাইন্ড অপারেশন ফলাফল socketB
। যদি প্রথম কলামটি বলে ON/OFF
, এর মান SO_REUSEADDR
ফলাফলের সাথে অপ্রাসঙ্গিক।
ঠিক আছে, SO_REUSEADDR
ওয়াইল্ডকার্ড ঠিকানাগুলিতে প্রভাব ফেলেছে, তা জেনে রাখা ভাল। তবুও এটি কেবল এটির প্রভাব নয়। আরও একটি সুপরিচিত প্রভাব রয়েছে যা বেশিরভাগ লোকেরা SO_REUSEADDR
সার্ভার প্রোগ্রামগুলিতে প্রথম স্থানে ব্যবহার করার কারণও । এই বিকল্পের অন্যান্য গুরুত্বপূর্ণ ব্যবহারের জন্য আমাদের টিসিপি প্রোটোকল কীভাবে কাজ করে তার একটি গভীর তদন্ত করতে হবে।
একটি সকেটের একটি প্রেরণ বাফার থাকে এবং যদি send()
ফাংশনটিতে কল সফল হয় তবে এর অর্থ এই নয় যে অনুরোধ করা ডেটা আসলেই প্রেরণ করা হয়েছে, এর অর্থ কেবলমাত্র প্রেরণ বাফারে ডেটা যুক্ত করা হয়েছে। ইউডিপি সকেটের জন্য, তাত্ক্ষণিকভাবে না হলে তথ্যগুলি খুব শীঘ্রই প্রেরণ করা হয়, তবে টিসিপি সকেটের জন্য, প্রেরণ বাফারে ডেটা যুক্ত করার এবং টিসিপি বাস্তবায়নের ক্ষেত্রে সেই ডেটা প্রেরণ করার মধ্যে তুলনামূলকভাবে দীর্ঘ বিলম্ব হতে পারে। ফলস্বরূপ, আপনি যখন কোনও টিসিপি সকেট বন্ধ করেন তখন প্রেরণ বাফারটিতে এখনও পেন্ডিং ডেটা থাকতে পারে, যা এখনও প্রেরণ করা হয়নি তবে আপনার কোডটি প্রেরিত হিসাবে বিবেচনা করে, যেহেতুsend()
কল সফল। যদি টিসিপি বাস্তবায়ন আপনার অনুরোধের সাথে সাথে সকেটটি বন্ধ করে দেয়, তবে এই সমস্ত ডেটা হারিয়ে যাবে এবং আপনার কোডটি সে সম্পর্কেও জানত না। বলা হয় টিসিপি একটি নির্ভরযোগ্য প্রোটোকল এবং ঠিক এর মতো ডেটা হারাতে খুব নির্ভরযোগ্য নয়। এজন্য একটি সকেট যা এখনও পাঠাতে ডেটা রাখে TIME_WAIT
আপনি যখন এটি বন্ধ করবেন তখন ডাকে এমন একটি রাজ্যে যাবে। সেই অবস্থায় এটি সমস্ত মুলতুবি থাকা ডেটা সফলভাবে প্রেরণ করা পর্যন্ত বা একটি সময়সীমা আঘাত না হওয়া পর্যন্ত অপেক্ষা করবে, সেক্ষেত্রে সকেটটি জোর করে বন্ধ করা হয়।
কার্টেলটি সকেটটি বন্ধ করার আগে যে পরিমাণ সময় অপেক্ষা করবে, নির্বিশেষে এটিতে ফ্লাইটে ডেটা রয়েছে কি না, তাকে লিংগার সময় বলে । গড়িমসি করা সময় (দুই মিনিট একটি সাধারণ মান অনেক সিস্টেমে পাবেন হয়) সবচেয়ে সিস্টেমে এবং ডিফল্ট বরং দীর্ঘ দ্বারা বিশ্বব্যাপী কনফিগার করা যাবে। এটি সকেট অপশনটি ব্যবহার করে প্রতি সকেটটি কনফিগার করা যায় SO_LINGER
যা সময়সীমা আরও কম বা আরও দীর্ঘ করতে এবং এমনকি এটি সম্পূর্ণরূপে অক্ষম করতে ব্যবহার করা যেতে পারে। এটি সম্পূর্ণরূপে নিষ্ক্রিয় করা একটি খুব খারাপ ধারণা, যদিও, টিসিপি সকেট বন্ধ করে দেওয়া কিছুটা জটিল প্রক্রিয়া এবং এতে কয়েকটি প্যাকেট প্রেরণ এবং ফিরে পাঠানো (পাশাপাশি প্যাকেটগুলি হারিয়ে যাওয়ার ক্ষেত্রে পুনরায় পাঠানো) এবং এই পুরো ঘনিষ্ঠ প্রক্রিয়াটি অন্তর্ভুক্ত রয়েছে লম্বা সময় দ্বারা সীমাবদ্ধ। আপনি যদি অলসতা অক্ষম করেন তবে আপনার সকেট কেবল ফ্লাইটে ডেটা হারাতে পারে না, এটি সর্বদা করুণাময়ের পরিবর্তে জোর করে বন্ধ করা হয়, যা সাধারণত সুপারিশ করা হয় না। টিসিপি সংযোগ কীভাবে বন্ধভাবে বন্ধ করা হয় সে সম্পর্কে বিশদটি এই উত্তরটির বাইরে নয়, আপনি যদি আরও জানতে চান তবে আমি আপনাকে এই পৃষ্ঠাটি একবার দেখুন বলে সুপারিশ করছি । এমনকি আপনি যদি অলস SO_LINGER
অবস্থায় অক্ষম হয়েও থাকেন , যদি আপনার প্রক্রিয়াটি স্পষ্টভাবে সকেটটি বন্ধ না করে মারা যায় তবে বিএসডি (এবং সম্ভবত অন্যান্য সিস্টেমগুলি) তবুও আপনার কনফিগার করা বিষয়গুলি উপেক্ষা করে দীর্ঘায়িত হবে। উদাহরণস্বরূপ এটি ঘটবে যদি আপনার কোডটি কেবল কল করেexit()
(ক্ষুদ্রতর, সাধারণ সার্ভার প্রোগ্রামগুলির জন্য বেশ সাধারণ) বা প্রক্রিয়াটি একটি সংকেত দ্বারা নিহত হয় (যার মধ্যে এটি একটি অবৈধ মেমরির অ্যাক্সেসের কারণে সহজেই ক্র্যাশ হওয়ার সম্ভাবনা রয়েছে)। সুতরাং সকেট সব পরিস্থিতিতে কখনই স্থায়ী হবে না তা নিশ্চিত করার জন্য আপনি যা করতে পারেন তা কিছুই নেই।
প্রশ্নটি হল, সিস্টেমটি কীভাবে একটি সকেটকে রাজ্যে আচরণ করে TIME_WAIT
? যদি SO_REUSEADDR
সেট না করা থাকে, রাষ্ট্রের একটি সকেট TIME_WAIT
এখনও উত্সের ঠিকানা এবং বন্দরের সাথে আবদ্ধ বলে মনে করা হয় এবং সকেটটি সত্যিই বন্ধ না হওয়া অবধি নতুন সকেটটিকে একই ঠিকানায় এবং বন্দরের সাথে বেঁধে রাখার যে কোনও প্রচেষ্টা ব্যর্থ হবে, এতে দীর্ঘ সময় লাগতে পারে দীর্ঘমেয়াদী সময় কনফিগার করা হিসাবে । সুতরাং এমন আশা করবেন না যে আপনি কোনও সকেটের বন্ধ করার সাথে সাথে তার উত্সের ঠিকানাটি পুনরায় ফিরিয়ে দিতে পারেন। বেশিরভাগ ক্ষেত্রে এটি ব্যর্থ হবে। তবে, আপনি যদি SO_REUSEADDR
সকেটের জন্য বাঁধাই করতে চেষ্টা করছেন তার জন্য সেট করা থাকলে, একই ঠিকানা এবং রাজ্যে বন্দরে আবদ্ধ আরেকটি সকেটTIME_WAIT
ইতোমধ্যে সমস্ত "অর্ধাহত" হয়ে যাওয়ার পরে কেবল তা উপেক্ষা করা হবে এবং আপনার সকেট কোনও সমস্যা ছাড়াই ঠিক একই ঠিক ঠিক ঠিক আবদ্ধ হতে পারে। সেক্ষেত্রে অন্যান্য সকেটের ঠিক একই ঠিকানা এবং বন্দর থাকতে পারে এমন কোনও ভূমিকা নেই। নোট করুন যে কোনও সকেটকে ঠিক একই ঠিকানা এবং বন্দরে TIME_WAIT
রাজ্যে মারা যাওয়ার মতো সকেটের সাথে আবদ্ধ হওয়ার ফলে অপ্রত্যাশিত এবং সাধারণত অনাকাঙ্ক্ষিত হতে পারে, অন্য সকেটটি এখনও "কর্মস্থলে" থাকলে পার্শ্ব প্রতিক্রিয়া হতে পারে, তবে এটি এই উত্তরটির পরিধি ছাড়িয়ে যায় এবং ভাগ্যক্রমে এই পার্শ্ব প্রতিক্রিয়াগুলি বাস্তবে বিরল।
আপনার সম্পর্কে একটি চূড়ান্ত বিষয় জানা উচিত SO_REUSEADDR
। উপরে লেখা সমস্ত কিছুই যতক্ষণ সকেটকে আবদ্ধ করতে চান ঠিকানার পুনরায় ব্যবহারের ক্ষমতা সক্ষম হবে। এটি আবশ্যক নয় যে অন্যান্য সকেট, যা ইতিমধ্যে আবদ্ধ বা একটি TIME_WAIT
অবস্থায় রয়েছে, যখন এটি আবদ্ধ ছিল তখনও এই পতাকাটি সেট ছিল। কোডটি স্থির করে দেয় যে বাঁধনটি সফল হবে বা ব্যর্থ হবে কিনা কেবলমাত্র কলটিতে SO_REUSEADDR
খাওয়ানো সকেটের bind()
পতাকাটি পরীক্ষা করে, অন্য সমস্ত সকেটের জন্য পরিদর্শন করা হয়েছে, এই পতাকাটির দিকেও তাকাতে হবে না।
SO_REUSEPORT
SO_REUSEPORT
বেশিরভাগ লোকেরা এমনটাই প্রত্যাশা করবে SO_REUSEADDR
। মূলত, SO_REUSEPORT
আপনাকে সকেট একটি অবাধ সংখ্যা সহিত আবদ্ধ করতে পারবেন ঠিক একই উৎস ঠিকানা এবং দীর্ঘ হিসাবে হিসাবে বন্দর সব এছাড়াও পূর্বে আবদ্ধ সকেট ছিল SO_REUSEPORT
আগে তারা বাধ্য হয় সেট। যদি প্রথম সকেট কোনও ঠিকানায় এবং বন্দরে আবদ্ধ থাকে না SO_REUSEPORT
, অন্য সকেটটি ঠিক একই ঠিকানা এবং বন্দরের সাথে আবদ্ধ হতে পারে না, নির্বিশেষে যদি অন্য সকেটটি SO_REUSEPORT
সেট করে থাকে বা না করে, যতক্ষণ না প্রথম সকেট তার বাঁধাই পুনরায় প্রকাশ না করে। SO_REUESADDR
কোড হ্যান্ডলিংয়ের বিপরীতে SO_REUSEPORT
কেবলমাত্র বর্তমানে সীমাবদ্ধ সকেট SO_REUSEPORT
সেট করেছে তা যাচাই করবে না তবে এটি যাচাই করার সময় একটি বিরোধী ঠিকানা এবং পোর্ট সহ সকেট সেট করেছিল তাও যাচাই করবে SO_REUSEPORT
।
SO_REUSEPORT
বোঝায় না SO_REUSEADDR
। এর অর্থ যদি কোনও সকেটটি SO_REUSEPORT
আবদ্ধ হওয়ার সময় সেট না করা থাকে এবং SO_REUSEPORT
ঠিক একই ঠিকানা এবং বন্দরের সাথে আবদ্ধ হওয়ার সাথে সাথে অন্য সকেট সেট করা থাকে, তবে বাইন্ডটি ব্যর্থ হয়, যা প্রত্যাশিত হয়, তবে অন্য সকেটটি ইতিমধ্যে মারা যাচ্ছে এবং এটি ব্যর্থ হয় and হয় TIME_WAIT
রাষ্ট্র। TIME_WAIT
রাজ্যের অন্য সকেট হিসাবে একই ঠিকানা এবং পোর্টে একটি সকেটকে বাঁধতে সক্ষম SO_REUSEADDR
হতে হয় সেই সকেটে সেট করা প্রয়োজন বা সেগুলি আবদ্ধ হওয়ার আগে উভয় সকেটে SO_REUSEPORT
সেট করা উচিত । অবশ্যই এটি উভয় সেট করার অনুমতি দেওয়া হয়, SO_REUSEPORT
এবং SO_REUSEADDR
, একটি সকেটে।
SO_REUSEPORT
এটি পরবর্তীকালে যুক্ত করা ছাড়া অন্য অনেক কিছুই বলার অপেক্ষা রাখে না SO_REUSEADDR
, এ কারণেই আপনি এটি অন্যান্য সিস্টেমের অনেক সকেট বাস্তবায়নে পাবেন না, যা এই বিকল্পটি যুক্ত হওয়ার আগে বিএসডি কোডটি "নকল" করেছিল, এবং এটি ছিল না এই বিকল্পের আগে বিএসডি-তে ঠিক একই সকেটের ঠিকানার সাথে দুটি সকেটকে আবদ্ধ করার উপায়।
কানেক্ট () EADDRINUSE ফিরছেন?
বেশিরভাগ লোকেরা জানেন যে bind()
ত্রুটিটি দিয়ে ব্যর্থ হতে পারে EADDRINUSE
, তবে, আপনি যখন ঠিকানা পুনরায় ব্যবহারের সাথে ঘুরেফিরে খেলা শুরু করবেন, আপনি সেই অদ্ভুত পরিস্থিতিতে পড়তে পারেন connect()
যা সেই ত্রুটিটিও ব্যর্থ হয়। এটা কিভাবে হতে পারে? কীভাবে কোনও সকেটে সংযোগ যুক্ত হওয়ার পরেও একটি দূরবর্তী ঠিকানা, ইতিমধ্যে ব্যবহারে থাকতে পারে? একাধিক সকেটকে ঠিক একই দূরবর্তী ঠিকানায় সংযুক্ত করার আগে কখনও সমস্যা হয়নি, তাই এখানে কী ঘটছে?
আমি যেমন আমার জবাবের একেবারে শীর্ষে বলেছি, একটি সংযোগ পাঁচটি মানের একটি দ্বিগুণ দ্বারা সংজ্ঞায়িত করা আছে, মনে আছে? এবং আমি আরও বলেছিলাম যে এই পাঁচটি মান অবশ্যই অনন্য হতে হবে অন্যথায় সিস্টেমটি আর দুটি সংযোগ আলাদা করতে পারে না, তাই না? ঠিক আছে, ঠিকানার পুনঃব্যবহারের সাথে আপনি একই উত্সের ঠিকানা এবং বন্দরে একই প্রোটোকলের দুটি সকেট বেঁধে রাখতে পারেন। এর অর্থ এই পাঁচটি মানের মধ্যে এই পাঁচটি মানের মধ্যে তিনটি ইতিমধ্যে একই। আপনি যদি এখন এই দুটি সকেটকে একই গন্তব্য ঠিকানা এবং বন্দরের সাথে সংযোগ স্থাপনের চেষ্টা করেন তবে আপনি দুটি সংযুক্ত সকেট তৈরি করবেন, যার টিপলগুলি একেবারে অভিন্ন। এটি কাজ করতে পারে না, কমপক্ষে টিসিপি সংযোগগুলির জন্য নয় (ইউডিপি সংযোগগুলি যাইহোক সত্যিকারের সংযোগ নয়)। দুটি সংযোগের যে কোনও একটিতে ডেটা উপস্থিত হলে, ডেটাটি কোন সংযোগের সাথে সম্পর্কিত তা সিস্টেমটি বলতে পারেনি।
সুতরাং যদি আপনি একই উত্সের ঠিকানা এবং বন্দরে একই প্রোটোকলের দুটি সকেট বেঁধে রাখেন এবং উভয়কে একই গন্তব্য ঠিকানা এবং বন্দরের connect()
সাথে EADDRINUSE
সংযুক্ত করার চেষ্টা করেন, তবে দ্বিতীয় সংকেতের সাথে সংযোগ স্থাপনের চেষ্টা করার ক্ষেত্রে ত্রুটিটি দিয়ে ব্যর্থ হবেন , যার অর্থ একটি পাঁচটি মানের একটি অভিন্ন টিপলযুক্ত সকেট ইতিমধ্যে সংযুক্ত।
মাল্টিকাস্ট অ্যাড্রেস
বেশিরভাগ লোক এই বিষয়টিকে উপেক্ষা করে যে মাল্টিকাস্ট ঠিকানাগুলি উপস্থিত রয়েছে তবে তারা বিদ্যমান। একত্রে যোগাযোগের জন্য ইউনিকাস্টের ঠিকানাগুলি ব্যবহার করার সময়, মাল্টিকাস্ট ঠিকানাগুলি এক থেকে বহু যোগাযোগের জন্য ব্যবহৃত হয়। আইপিভি about সম্পর্কে জানতে পেরে বেশিরভাগ লোক মাল্টিকাস্ট ঠিকানাগুলি সম্পর্কে সচেতন হন তবে আইপিভি 4-তে মাল্টিকাস্ট ঠিকানাগুলিও বিদ্যমান ছিল, যদিও এই বৈশিষ্ট্যটি সর্বজনীন ইন্টারনেটে কখনও ব্যাপকভাবে ব্যবহৃত হয়নি।
SO_REUSEADDR
মাল্টিকাস্ট ঠিকানাগুলির পরিবর্তনের অর্থ হিসাবে এটি একাধিক সকেটগুলিকে উত্স মাল্টিকাস্ট ঠিকানা এবং পোর্টের ঠিক একই সংমিশ্রণে আবদ্ধ হতে দেয়। অন্য কথায়, মাল্টিকাস্ট অ্যাড্রেসগুলি ইউনিকাস্টের ঠিকানার SO_REUSEADDR
মতো ঠিক আচরণ করে SO_REUSEPORT
। বাস্তবিক, কোড একইরূপে SO_REUSEADDR
এবং SO_REUSEPORT
মাল্টিকাস্ট ঠিকানার জন্য অভিন্নরুপে, তার মানে আপনি যে বলতে পারে SO_REUSEADDR
বোঝা SO_REUSEPORT
সব মাল্টিকাস্ট ঠিকানাগুলি এবং অন্যান্য উপায় বৃত্তাকার জন্য।
FreeBSD 'র / OpenBSD / NetBSD বা
এগুলি সমস্ত মূল বিএসডি কোডের দেরী কাঁটাচামচ, এজন্য তারা তিনটিই বিএসডি হিসাবে একই বিকল্প প্রস্তাব করে এবং তারা বিএসডি-র মতো একই আচরণ করে।
ম্যাকোস (ম্যাকস এক্স)
এর মূল ভিত্তিতে , ম্যাকোস কেবলমাত্র বিএসডি কোডের (বিএসডি ৪.৩) দেরী কাঁটাচামচ ভিত্তি করে " ডারউইন " নামে একটি বিএসডি-স্টাইলের ইউএনআইএক্স , যা পরবর্তী সময়ে ফ্রিবিএসডি-র সাথে পুনরায় সংশ্লেষিত হয়েছিল ম্যাক ওএস 10.3 রিলিজের জন্য 5 কোড বেস, যাতে অ্যাপল সম্পূর্ণ পসিক্স সম্মতি অর্জন করতে পারে (ম্যাকোস পসিক্স প্রত্যয়িত)। এর মূল (" ম্যাক ") এ একটি মাইক্রোকার্নেল থাকা সত্ত্বেও , বাকি কার্নেল (" এক্সএনইউ ") মূলত কেবল একটি বিএসডি কার্নেল, এবং সে কারণেই ম্যাকোস বিএসডি হিসাবে একই বিকল্পগুলি সরবরাহ করে এবং তারা বিএসডি-র মতো একই আচরণ করে ve ।
আইওএস / ওয়াচওএস / টিভিএস
আইওএস হ'ল সামান্য সংশোধিত এবং ছাঁটাই করা কার্নেল সহ একটি ম্যাকোস কাঁটাচামচ, কিছুটা ব্যবহারকারীর স্পেস টুলসেট এবং কিছুটা আলাদা ডিফল্ট ফ্রেমওয়ার্ক সেট সেট করে। ওয়াচওএস এবং টিভিওএস হ'ল আইওএস কাঁটাচামচ, যা আরও নিচে নামানো হয় (বিশেষত ওয়াচওএস)। আমার সর্বোত্তম জ্ঞানের জন্য তারা সকলেই ম্যাকওএসের মতোই আচরণ করে।
লিনাক্স
লিনাক্স <3.9
লিনাক্স ৩.৯-এর পূর্বে কেবলমাত্র বিকল্প উপস্থিত SO_REUSEADDR
ছিল। এই বিকল্পটি সাধারণত দুটি গুরুত্বপূর্ণ ব্যতিক্রম সহ BSD এর মতো আচরণ করে:
যতক্ষণ শ্রবণকারী (সার্ভার) টিসিপি সকেট নির্দিষ্ট পোর্টের সাথে আবদ্ধ থাকে, SO_REUSEADDR
সেই পোর্টকে লক্ষ্য করে সমস্ত সকেটের জন্য বিকল্পটি সম্পূর্ণভাবে উপেক্ষা করা হবে। দ্বিতীয় সকেটকে একই বন্দরে বাঁধাই কেবল তখনই সম্ভব যখন SO_REUSEADDR
সেট না করে BSD এও সম্ভব ছিল । যেমন আপনি একটি ওয়াইল্ডকার্ড ঠিকানার সাথে বাঁধাই করতে পারবেন না এবং তারপরে আরও নির্দিষ্ট একটি বা অন্য পথে গোল করতে পারবেন, যদি সেট করে থাকেন তবে উভয়ই BSD এ সম্ভব SO_REUSEADDR
। আপনি যা করতে পারেন তা হ'ল সর্বদা অনুমোদিত হিসাবে আপনি একই বন্দর এবং দুটি ভিন্ন নন-ওয়াইল্ডকার্ড ঠিকানার সাথে আবদ্ধ থাকতে পারেন। এই দিকটিতে বিএসডি-র চেয়ে লিনাক্স বেশি বিধিনিষেধযুক্ত।
দ্বিতীয় ব্যতিক্রম হ'ল ক্লায়েন্ট সকেটের ক্ষেত্রে, এই বিকল্পটি SO_REUSEPORT
BSD এর মতো ঠিক আচরণ করে , যতক্ষণ না উভয়ই এই পতাকাটি আবদ্ধ হওয়ার আগেই সেট করে রেখেছিল set এটির অনুমতি দেওয়ার কারণটি কেবল এটি ছিল যে বিভিন্ন প্রোটোকলের জন্য একই ইউডিপি সকেটের ঠিকানার সাথে একাধিক সকেটকে আবদ্ধ করতে সক্ষম হওয়া গুরুত্বপূর্ণ এবং SO_REUSEPORT
3.9-এর পূর্বে কোনও ব্যবহার ছিল না , SO_REUSEADDR
সেই ফাঁকটি পূরণ করার জন্য সেই আচরণের পরিবর্তন অনুসারে পরিবর্তন করা হয়েছিল । সেই দিক থেকে বিএসডি-র তুলনায় লিনাক্স কম সীমাবদ্ধ।
লিনাক্স> = 3.9
লিনাক্স ৩.৯ লিনাক্সে অপশনও যুক্ত করেছে SO_REUSEPORT
। এই বিকল্পটি বিএসডি-তে বিকল্পের মতো হুবহু আচরণ করে এবং ঠিক একই ঠিকানা এবং পোর্ট সংখ্যায় বাধ্যতামূলক অনুমতি দেয় যতক্ষণ না সমস্ত সকেটকে বাঁধানোর আগে এই বিকল্পটি সেট করা থাকে।
তবুও, SO_REUSEPORT
অন্যান্য সিস্টেমে এখনও দুটি পার্থক্য রয়েছে :
"পোর্ট হাইজ্যাকিং" রোধ করতে একটি বিশেষ সীমাবদ্ধতা রয়েছে: একই ঠিকানা এবং পোর্ট সংমিশ্রণটি ভাগ করতে চায় এমন সমস্ত সকেটগুলি অবশ্যই কার্যকর কার্যকর আইডি ভাগ করে নেওয়ার প্রক্রিয়াগুলির সাথে সম্পর্কিত হতে পারে! সুতরাং এক ব্যবহারকারী অন্য ব্যবহারকারীর পোর্ট "চুরি" করতে পারে না। নিখোঁজ SO_EXCLBIND
/ SO_EXCLUSIVEADDRUSE
পতাকাগুলির জন্য কিছুটা ক্ষতিপূরণ দেওয়ার জন্য এটি কিছু বিশেষ যাদু ।
অতিরিক্তভাবে কার্নেল SO_REUSEPORT
সকেটগুলির জন্য কিছু "বিশেষ যাদু" সম্পাদন করে যা অন্যান্য অপারেটিং সিস্টেমগুলিতে পাওয়া যায় না: ইউডিপি সকেটের জন্য, এটি সমানভাবে ডেটাগ্রাম বিতরণ করার চেষ্টা করে, টিসিপি শ্রবণকারী সকেটের জন্য, এটি আগত সংযোগের অনুরোধগুলি বিতরণ করার চেষ্টা করে (কল করে তারা গ্রহণ করে accept()
) একই ঠিকানা এবং পোর্ট সংমিশ্রণটি ভাগ করে এমন সমস্ত সকেটে সমানভাবে এইভাবে একটি অ্যাপ্লিকেশন সহজেই একাধিক শিশু প্রসেসগুলিতে একই পোর্টটি খুলতে পারে এবং তারপরে SO_REUSEPORT
একটি খুব সস্তা লোড ব্যালেন্সিং পেতে ব্যবহার করতে পারে use
অ্যান্ড্রয়েড
যদিও পুরো অ্যান্ড্রয়েড সিস্টেম বেশিরভাগ লিনাক্স ডিস্ট্রিবিউশন থেকে কিছুটা পৃথক, এর মূল অংশে কিছুটা পরিবর্তিত লিনাক্স কার্নেল কাজ করে, সুতরাং লিনাক্সের ক্ষেত্রে প্রযোজ্য প্রতিটি জিনিসই অ্যান্ড্রয়েডেও প্রয়োগ করা উচিত।
উইন্ডোজ
উইন্ডোজ কেবল SO_REUSEADDR
বিকল্পটি জানে , নেই SO_REUSEPORT
। সেট SO_REUSEADDR
সেটিং মত উইন্ডোজ আচরণ করবে একটি সকেট উপর SO_REUSEPORT
এবং SO_REUSEADDR
বাসদ একটি সকেট উপর, একটি ব্যতিক্রমের সঙ্গে: সঙ্গে একটি সকেট SO_REUSEADDR
সবসময় করতে পারেন বেঁধে ঠিক একই উৎস ঠিকানা এবং ইতিমধ্যে আবদ্ধ সকেট যেমন বন্দর, এর এমনকি যদি অন্যান্য সকেট এই অপশনটি ছিল না এটি আবদ্ধ যখন সেট । এই আচরণটি কিছুটা বিপজ্জনক কারণ এটি কোনও অ্যাপ্লিকেশনটিকে অন্য অ্যাপ্লিকেশনের সংযুক্ত পোর্ট "চুরি" করতে দেয়। এটি বলার অপেক্ষা রাখে না যে এতে বড় ধরনের সুরক্ষা জড়িত থাকতে পারে। মাইক্রোসফ্ট বুঝতে পেরেছিল যে এটি একটি সমস্যা হতে পারে এবং এইভাবে অন্য সকেট বিকল্প যুক্ত করেছে SO_EXCLUSIVEADDRUSE
। বিন্যাসSO_EXCLUSIVEADDRUSE
একটি সকেটে নিশ্চিত করে তোলে যে যদি বাঁধাই সফল হয় তবে উত্স ঠিকানা এবং পোর্টের সংমিশ্রণটি এই সকেটের একচেটিয়া মালিকানাধীন এবং অন্য কোনও সকেট তাদের কাছে আবদ্ধ করতে পারে না, এমনকি এটি SO_REUSEADDR
সেট করা থাকলেও নয় ।
উইন্ডোজে ফ্ল্যাগগুলি কীভাবে কাজ করে SO_REUSEADDR
এবং SO_EXCLUSIVEADDRUSE
কীভাবে বাধ্যতামূলক / পুনরায় বাঁধাইয়ের উপর প্রভাব ফেলবে সে সম্পর্কে আরও তথ্যের জন্য মাইক্রোসফ্ট দয়া করে সেই উত্তরটির শীর্ষের কাছে আমার টেবিলের অনুরূপ একটি টেবিল সরবরাহ করেছিলেন। কেবল এই পৃষ্ঠাটি দেখুন এবং কিছুটা নিচে স্ক্রোল করুন। প্রকৃতপক্ষে তিনটি টেবিল রয়েছে, প্রথমটি পুরানো আচরণ (পূর্ববর্তী উইন্ডোজ 2003) প্রদর্শন করে, দ্বিতীয়টি আচরণ (উইন্ডোজ 2003 এবং তারপরে) এবং তৃতীয়টি দেখায় যে উইন্ডোজ 2003 এ আচরণটি কীভাবে পরিবর্তিত হয় এবং পরে যদি bind()
কলগুলি করা হয় তবে বিভিন্ন ব্যবহারকারী
সোলারিস
সোলারিস হলেন সানোসের উত্তরসূরি। সুনোস মূলত বিএসডি, সুনোস 5 এর কাঁটাচালনার উপর ভিত্তি করে তৈরি হয়েছিল এবং পরে এটি এসভিআর 4 এর একটি কাঁটাচামচ ভিত্তিক ছিল, তবে এসভিআর 4 বিএসডি, সিস্টেম ভি এবং জেনিক্সের সংমিশ্রণ, সুতরাং কিছুটা ডিগ্রি অবধি সোলারিস একটি বিএসডি কাঁটাচামচ এবং একটি বরং এক প্রথম। ফলস্বরূপ সোলারিস কেবল জানেন SO_REUSEADDR
, নেই SO_REUSEPORT
। SO_REUSEADDR
আচরণ করবে কাছাকাছি একই যেমন বাসদ মধ্যে আছে। আমি যতদূর জানি SO_REUSEPORT
সোলারিসের মতো একই আচরণ করার কোনও উপায় নেই , এর অর্থ হ'ল দুটি সকেটকে ঠিক একই ঠিকানা এবং বন্দরে আবদ্ধ করা সম্ভব নয়।
উইন্ডোজের মতো সোলারিসের একটি সকেটকে একটি এক্সক্লুসিভ বাইন্ডিং দেওয়ার বিকল্প রয়েছে। এই বিকল্পটির নামকরণ করা হয়েছে SO_EXCLBIND
। যদি এই বিকল্পটি কোনও সকেটে বাঁধানোর আগে সেট করা থাকে, SO_REUSEADDR
যদি দুটি সকেটের ঠিকানা সংঘাতের জন্য পরীক্ষা করা হয় তবে অন্য সকেটে সেট করার কোনও প্রভাব নেই। যেমন যদি socketA
একটি ওয়াইল্ড কার্ড ঠিকানায় আবদ্ধ হয় এবং socketB
হয়েছে SO_REUSEADDR
সক্ষম এবং একটি অ-ওয়াইল্ডকার্ড ঠিকানা এবং একই বন্দর আবদ্ধ হয় socketA
, এই বেঁধে স্বাভাবিকভাবে সফল হবে, যদি না socketA
ছিল SO_EXCLBIND
সক্রিয়, যে ক্ষেত্রে এটা নির্বিশেষে ব্যর্থ হবে SO_REUSEADDR
পতাকা socketB
।
অন্যান্য সিস্টেম
যদি আপনার সিস্টেমটি উপরে তালিকাভুক্ত না হয়, আমি একটি সামান্য পরীক্ষা প্রোগ্রাম লিখেছিলাম যা আপনি আপনার সিস্টেম এই দুটি বিকল্পকে কীভাবে পরিচালনা করে তা জানতে ব্যবহার করতে পারেন। এছাড়াও আপনি যদি আমার ফলাফলগুলি ভুল বলে মনে করেন তবে দয়া করে কোনও মন্তব্য পোস্ট করার আগে এবং সম্ভবত ভুল দাবি করার আগে প্রথমে সেই প্রোগ্রামটি চালান।
কোডটি যে বিল্ডিংয়ের জন্য প্রয়োজন তা হ'ল কিছুটা POSIX API (নেটওয়ার্ক অংশগুলির জন্য) এবং একটি C99 সংকলক (আসলে বেশিরভাগ নন- C99 সংকলক পাশাপাশি তারা যতক্ষণ কাজ করবে ততক্ষণ কাজ করবে inttypes.h
এবং stdbool.h
উদাহরণস্বরূপ gcc
পুরো সি 99 সমর্থন দেওয়ার আগে উভয় দীর্ঘই সমর্থিত) ।
প্রোগ্রামটি চালানোর জন্য যা প্রয়োজন তা হ'ল আপনার সিস্টেমে কমপক্ষে একটি ইন্টারফেসের (স্থানীয় ইন্টারফেস বাদে) একটি আইপি ঠিকানা বরাদ্দ রয়েছে এবং একটি ডিফল্ট রুট সেট করা হয় যা সেই ইন্টারফেসটি ব্যবহার করে। প্রোগ্রামটি সেই আইপি ঠিকানাটি সংগ্রহ করবে এবং এটি দ্বিতীয় "নির্দিষ্ট ঠিকানা" হিসাবে ব্যবহার করবে।
এটি সমস্ত সম্ভাব্য সংমিশ্রণগুলির পরীক্ষা করে যা আপনি ভাবতে পারেন:
- টিসিপি এবং ইউডিপি প্রোটোকল
- সাধারণ সকেট, শোন (সার্ভার) সকেট, মাল্টিকাস্ট সকেট
SO_REUSEADDR
সকেট 1, সকেট 2, বা উভয় সকেটে সেট করুন
SO_REUSEPORT
সকেট 1, সকেট 2, বা উভয় সকেটে সেট করুন
- আপনার সমস্ত ঠিকানা সংমিশ্রণগুলি
0.0.0.0
(ওয়াইল্ডকার্ড), 127.0.0.1
(নির্দিষ্ট ঠিকানা), এবং দ্বিতীয় নির্দিষ্ট ঠিকানাটি আপনার প্রাথমিক ইন্টারফেসে পাওয়া যায় (মাল্টিকাস্টের জন্য এটি কেবল 224.1.2.3
সমস্ত পরীক্ষার মধ্যে রয়েছে)
এবং ফলাফলগুলি একটি ভাল টেবিলে মুদ্রণ করে। এটি এমন সিস্টেমেও কাজ করবে যা জানে না SO_REUSEPORT
, এই ক্ষেত্রে এই বিকল্পটি কেবল পরীক্ষা করা হয় না।
প্রোগ্রামটি সহজে যা পরীক্ষা করতে পারে না তা হ'ল কীভাবে রাজ্যে SO_REUSEADDR
সকেটে কাজ করে TIME_WAIT
কেননা সেই অবস্থায় সকেটকে জোর করা এবং রাখা খুব জটিল। ভাগ্যক্রমে বেশিরভাগ অপারেটিং সিস্টেমগুলি এখানে BSD এর মতো আচরণ করে এবং বেশিরভাগ সময় প্রোগ্রামাররা কেবল সেই রাজ্যের অস্তিত্ব উপেক্ষা করতে পারে।
এখানে কোডটি রয়েছে (আমি এটিকে এখানে অন্তর্ভুক্ত করতে পারি না, উত্তরের একটি আকার সীমা থাকে এবং কোড এই উত্তরটিকে সীমা ছাড়িয়ে যায়)।
INADDR_ANY
বাঁধাই বিদ্যমান স্থানীয় ঠিকানাগুলিকে আবদ্ধ করে না, তবে ভবিষ্যতের সমস্ত ঠিকানাও আবদ্ধ করে।listen
আপনি অবশ্যই বলেছিলেন এমনটা সত্ত্বেও একই সঠিক প্রোটোকল, স্থানীয় ঠিকানা এবং স্থানীয় পোর্ট সহ সকেট তৈরি করে।