
डिवाइसों को जोड़कर सूचना का आदान–प्रदान कराना ही नेटवर्किंग का मूल है। सॉकेट प्रभावी नेटवर्क संचार का एक आवश्यक हिस्सा हैं, क्योंकि ये स्थानीय या वैश्विक नेटवर्कों पर डिवाइसों के बीच तथा एक ही मशीन पर विभिन्न प्रक्रियाओं के बीच संदेश भेजने के लिए आधारभूत अवधारणा हैं। ये एक लो-लेवल इंटरफ़ेस प्रदान करते हैं, जो भेजे या प्राप्त किए जाने वाले ट्रैफ़िक पर सूक्ष्म-स्तरीय नियंत्रण देता है।
यह लो-लेवल प्रकृति विशेष उपयोग-केस के लिए बहुत कम ओवरहेड के साथ अत्यधिक प्रदर्शनकारी कम्युनिकेशन चैनल (या कस्टम प्रोटोकॉल) बनाना संभव बनाती है—वे ओवरहेड जो पारंपरिक प्रोटोकॉल में हो सकते हैं, जो स्वयं सॉकेट कम्युनिकेशन के ऊपर बने होते हैं।
यही कारण है कि सॉकेट रियल-टाइम क्लाइंट–सर्वर अनुप्रयोगों में असाधारण रूप से उपयोगी होते हैं, जो त्वरित संदेश-विनिमय पर निर्भर रहते हैं या बहुत बड़े डेटा वॉल्यूम पर काम करते हैं।
इस लेख में, हम सॉकेट प्रोग्रामिंग की बुनियाद समझेंगे और Python का उपयोग करके सॉकेट-आधारित क्लाइंट और सर्वर अनुप्रयोग बनाने की चरण-दर-चरण मार्गदर्शिका देंगे।
नेटवर्किंग की बुनियादी बातें
नेटवर्किंग किसी भी तरह के संचार और सूचना-साझाकरण को सक्षम बनाती है। ऐसे परस्पर जुड़े डिवाइसों के समूह को नेटवर्क कहा जाता है।
हम अपने भौतिक जगत में कई प्रकार के नेटवर्क देखते हैं: एयरलाइन या पावरलाइन नेटवर्क, या हाईवे से एक-दूसरे से जुड़े शहर—ये कुछ अच्छे उदाहरण हैं।
ठीक उसी तरह, सूचना प्रौद्योगिकी में भी असंख्य नेटवर्क हैं; जिनमें सबसे प्रमुख और प्रसिद्ध है इंटरनेट—नेटवर्कों का वैश्विक नेटवर्क—जो असंख्य डिवाइसों को जोड़ता है, और संभवतः आप अभी यही लेख पढ़ने के लिए इसका उपयोग कर रहे हैं।
नेटवर्क के प्रकार
इंटरनेट स्वयं कई और नेटवर्कों का समूह है, जो आकार या अन्य गुणों में भिन्न होते हैं: उदाहरण के लिए, लोकल एरिया नेटवर्क (LAN), जो आमतौर पर पास–पास स्थित कंप्यूटरों को जोड़ते हैं। कंपनियों या अन्य संस्थानों (बैंक, विश्वविद्यालय आदि) में मशीनें या आपके घर के राउटर से जुड़े डिवाइस, ऐसे नेटवर्क बनाते हैं।
इसके अलावा बड़े या छोटे प्रकार के नेटवर्क भी होते हैं जैसे PAN (पर्सनल एरिया नेटवर्क), जो बस आपका स्मार्टफोन ब्लूटूथ से लैपटॉप से जुड़ा होना हो सकता है; MAN (मेट्रोपॉलिटन एरिया नेटवर्क), जो पूरे शहर के डिवाइसों को इंटरकनेक्ट कर सकता है; और WAN (वाइड एरिया नेटवर्क), जो पूरे देशों या विश्व को कवर कर सकते हैं। और हाँ, सबसे बड़ा WAN स्वयं इंटरनेट है।
यह कहना अनावश्यक है कि कंप्यूटर नेटवर्क बहुत जटिल हो सकते हैं और अनेक घटकों से मिलकर बनते हैं। इनमें से सबसे बुनियादी और महत्वपूर्ण प्रिमिटिव है—कम्युनिकेशन प्रोटोकॉल।
नेटवर्क कम्युनिकेशन प्रोटोकॉल के प्रकार
कम्युनिकेशन प्रोटोकॉल यह नियम तय करते हैं कि सूचना कैसे और किस फ़ॉर्मेट में भेजी और प्राप्त की जानी चाहिए। इन प्रोटोकॉलों को एक पदानुक्रम में व्यवस्थित किया जाता है ताकि नेटवर्क संचार से जुड़े विभिन्न कार्यों का प्रबंधन किया जा सके।
कुछ सामान्य और व्यापक रूप से प्रसिद्ध नेटवर्क कम्युनिकेशन प्रोटोकॉल हैं:
Wi‑Fi
लिंक लेयर प्रोटोकॉल का उदाहरण, यानी यह हार्डवेयर के बहुत करीब बैठता है और वायरलेस वातावरण में एक डिवाइस से दूसरे तक डेटा को शारीरिक रूप से भेजने के लिए ज़िम्मेदार होता है।
IP (Internet Protocol)
IP एक नेटवर्क लेयर प्रोटोकॉल है जो मुख्यतः पैकेट रूटिंग और IP एड्रेसिंग के लिए ज़िम्मेदार है।
TCP (Transmission Control Protocol)
एक भरोसेमंद, कनेक्शन-ओरिएंटेड प्रोटोकॉल जो फुल डुप्लेक्स संचार प्रदान करता है और डेटा की अखंडता व डिलीवरी सुनिश्चित करता है। यह एक ट्रांसपोर्ट लेयर प्रोटोकॉल है, जो कनेक्शनों का प्रबंधन करता है, त्रुटियाँ पहचानता है, और सूचना प्रवाह को नियंत्रित करता है।
UDP (User Datagram Protocol)
TCP के ही प्रोटोकॉल सूट का एक प्रोटोकॉल। मुख्य अंतर यह है कि UDP सरल, तेज़, लेकिन अविश्वसनीय कनेक्शनलेस प्रोटोकॉल है, जो किसी डिलीवरी जाँच को अंजाम नहीं देता और “फायर-एंड-फ़ॉरगेट” प्रतिमान का अनुसरण करता है। TCP की तरह UDP भी ट्रांसपोर्ट लेयर पर स्थित है।
HTTP (Hypertext Transfer Protocol)
एप्लिकेशन लेयर का प्रोटोकॉल और वेब पर ब्राउज़र-टू-सर्वर संचार के लिए सबसे अधिक प्रयुक्त प्रोटोकॉल, विशेषकर वेबसाइट सर्व करने के लिए। यह कहने की आवश्यकता नहीं कि आप जो लेख अभी पढ़ रहे हैं, वह भी HTTP के माध्यम से सर्व हुआ है। HTTP, TCP के ऊपर बनता है और वेब एप्लिकेशन से संबंधित सूचना जैसे हेडर (जो मेटाडेटा और कुकीज़ ट्रांसफर करने में काम आते हैं), विभिन्न HTTP मेथड (GET, POST, DELETE, UPDATE) आदि का प्रबंधन और ट्रांसफ़र करता है।
MQTT (Message Queue Telemetry Transport)
एप्लिकेशन-स्तर के एक अन्य प्रोटोकॉल का उदाहरण, जिसका उपयोग सीमित प्रोसेसिंग पावर और बैटरी लाइफ़ वाले डिवाइसों में, अविश्वसनीय नेटवर्क परिस्थितियों में किया जाता है (उदाहरण के लिए, खनन स्थल पर गैस सेंसर या आपके घर में स्मार्ट बल्ब)। MQTT, IoT (Internet of Things) में प्रयुक्त मानक मैसेजिंग प्रोटोकॉल है। यह हल्का और उपयोग में सरल है, और विश्वसनीयता बढ़ाने के लिए रिट्रांसमिशन जैसे बिल्ट-इन मैकेनिज़्म के साथ डिज़ाइन किया गया है। यदि आप इस प्रोटोकॉल का Python के साथ उपयोग करने में रुचि रखते हैं, तो आप यह Python MQTT गाइड पढ़ सकते हैं, जो Paho MQTT क्लाइंट का गहन अवलोकन देती है।
एक महत्वपूर्ण बात यह है कि उपर्युक्त सभी प्रोटोकॉल आंतरिक रूप से सॉकेट का उपयोग करते हैं, लेकिन उनके ऊपर अपनी स्वयं की लॉजिक और डेटा प्रोसेसिंग जोड़ते हैं। इसका कारण यह है कि आधुनिक डिवाइसों में किसी भी नेटवर्क संचार के लिए सॉकेट लो-लेवल इंटरफ़ेस का कार्य करते हैं—जैसा हम अगले खंड में चर्चा करेंगे।
मुख्य अवधारणाएँ और शब्दावली
स्वाभाविक रूप से, नेटवर्क के संदर्भ में और भी कई महत्वपूर्ण अवधारणाएँ और शब्द हैं। यहाँ उन प्रमुख बातों का संक्षिप्त विवरण है, जो आगे ट्यूटोरियल में सामने आ सकती हैं:
- पैकेट: कंप्यूटर नेटवर्क में डेटा ट्रांसमिशन की मानक इकाई (बोलचाल में इसे “मैसेज” से तुलना कर सकते हैं)।
- एंडपॉइंट: वह गंतव्य जहाँ पैकेट पहुँचते हैं।
- IP पता: एक संख्यात्मक पहचानकर्ता जो नेटवर्क पर किसी डिवाइस की विशिष्ट पहचान करता है। IP पते का एक उदाहरण: 192.168.0.0
- पोर्ट: एक संख्यात्मक पहचानकर्ता जो किसी डिवाइस पर चल रही प्रक्रिया की विशिष्ट पहचान करता है, जो विशेष नेटवर्क संचार संभालती है: जैसे HTTP पर आपकी वेबसाइट सर्व करना। जहाँ IP पता डिवाइस की पहचान करता है, वहीं पोर्ट एप्लिकेशन की पहचान करता है (हर एप्लिकेशन एक प्रक्रिया होता है या प्रक्रियाओं से बना होता है)। कुछ प्रसिद्ध पोर्ट उदाहरण: पोर्ट 80, जिसे परंपरागत रूप से सर्वर एप्लिकेशन HTTP ट्रैफ़िक के लिए उपयोग करते हैं, और पोर्ट 443 HTTPS (सुरक्षित HTTP) के लिए।
- गेटवे: नेटवर्क का एक विशेष प्रकार का नोड (डिवाइस) जो एक नेटवर्क से दूसरे में प्रवेश बिंदु का कार्य करता है। ये नेटवर्क अलग-अलग प्रोटोकॉल भी इस्तेमाल कर सकते हैं, इसलिए गेटवे को प्रोटोकॉल ट्रांसलेशन भी करना पड़ सकता है। गेटवे का उदाहरण एक राउटर है, जो घर के लोकल नेटवर्क को इंटरनेट से जोड़ता है।
सॉकेट को समझना
सॉकेट क्या है?
सॉकेट, एक इंटरफ़ेस (द्वार) है जो एक ही या भिन्न मशीनों पर स्थित विभिन्न प्रक्रियाओं के बीच संचार की सुविधा देता है। बाद वाले मामले में, हम नेटवर्क सॉकेट की बात करते हैं।
नेटवर्क सॉकेट कनेक्शन प्रबंधन का एब्स्ट्रैक्शन प्रदान करते हैं। खासकर Unix सिस्टमों में, सॉकेट मूलतः ऐसे फ़ाइलें हैं, जो वही write-read ऑपरेशन सपोर्ट करती हैं, लेकिन सारा डेटा नेटवर्क पर भेजती हैं।
जब कोई सॉकेट listening या connecting अवस्था में होता है, तो वह हमेशा IP पते और पोर्ट नंबर के संयोजन से बंधा होता है, जो होस्ट (मशीन/डिवाइस) और प्रक्रिया की पहचान करता है।
सॉकेट कनेक्शन कैसे काम करते हैं
सॉकेट इनकमिंग कनेक्शनों को सुन सकते हैं या स्वयं आउटबाउंड कनेक्शन कर सकते हैं। जब कनेक्शन स्थापित हो जाता है, तो listening सॉकेट (सर्वर सॉकेट) अतिरिक्त रूप से कनेक्ट होने वाली साइड के IP और पोर्ट से भी बाइंड हो जाता है।
या वैकल्पिक रूप से, एक नया सॉकेट बनाया जाता है जो अब लिस्नर और रिक्वेस्टर के IP अड्रेस और पोर्ट नंबर की दो जोड़ियों से बंधा होता है। इस तरह, अलग मशीनों पर मौजूद दो जुड़े सॉकेट एक-दूसरे की पहचान कर सकते हैं और डेटा ट्रांसमिशन के लिए एक ही कनेक्शन साझा कर सकते हैं, बिना listening सॉकेट को ब्लॉक किए, जो इस बीच अन्य कनेक्शनों को सुनता रहता है।
कनेक्टिंग सॉकेट (क्लाइंट सॉकेट) के मामले में, कनेक्शन शुरू करते समय यह स्वतः ही डिवाइस के IP पते और किसी उपलब्ध रैंडम पोर्ट से बाइंड हो जाता है। फिर, कनेक्शन स्थापित होने पर, दूसरी साइड के IP और पोर्ट से भी वैसा ही बाइंड होता है जैसा listening सॉकेट के लिए होता है, लेकिन नया सॉकेट बनाए बिना।
सॉकेट प्रोग्रामिंग
जब हम सॉकेट प्रोग्रामिंग की बात करते हैं, तो हम अपने कोड में सॉकेट ऑब्जेक्ट बनाते हैं और उन पर ऑपरेशन करते हैं (listen, connect, receive, send आदि)। इस संदर्भ में, सॉकेट हमारे प्रोग्राम में बनाए गए विशेष ऑब्जेक्ट हैं, जिनमें नेटवर्क कनेक्शनों और ट्रैफ़िक के साथ काम करने के लिए विशेष मेथड होते हैं।
अंदरूनी तौर पर ये मेथड आपके ऑपरेटिंग सिस्टम कर्नेल—विशेष रूप से नेटवर्क स्टैक—को कॉल करते हैं, जो नेटवर्क ऑपरेशनों के प्रबंधन के लिए कर्नेल का विशेष हिस्सा होता है।
सॉकेट और क्लाइंट–सर्वर संचार
सॉकेट कनेक्शनों से जुड़े हैं; वे कनेक्शन हैंडलर होते हैं। वेब पर, जब भी आप कुछ डेटा भेजना या प्राप्त करना चाहते हैं, आप एक कनेक्शन आरंभ करते हैं (जो सॉकेट नामक इंटरफ़ेस के माध्यम से आरंभ होता है)।
अब, या तो आप या जिससे आप कनेक्ट होना चाहते हैं, वह सर्वर की भूमिका निभाता है, और दूसरी पार्टी क्लाइंट की। जहाँ सर्वर, क्लाइंटों को डेटा सर्व करता है, वहीं क्लाइंट सक्रिय रूप से कनेक्ट होते हैं और सर्वर से डेटा का अनुरोध करते हैं। सर्वर एक listening सॉकेट के माध्यम से नए कनेक्शनों को सुनता है, उन्हें स्थापित करता है, क्लाइंट के अनुरोध प्राप्त करता है और अपने उत्तर में अनुरोधित डेटा भेजता है।
दूसरी ओर, एक क्लाइंट उस सर्वर के IP पते और पोर्ट का उपयोग करके सॉकेट बनाता है जिससे उसे कनेक्ट होना है, कनेक्शन शुरू करता है, सर्वर को अपना अनुरोध भेजता है, और जवाब में डेटा प्राप्त करता है। क्लाइंट और सर्वर सॉकेटों के बीच यह निर्बाध सूचना-विनिमय अनेक नेटवर्क अनुप्रयोगों की रीढ़ है।
नेटवर्क प्रोटोकॉल के आधार के रूप में सॉकेट
यह तथ्य कि सॉकेट आधार बनते हैं, यह भी दर्शाता है कि उनके ऊपर कई प्रोटोकॉल बनाए और उपयोग किए जाते हैं। बहुत सामान्य हैं UDP और TCP, जिनका हम पहले ही संक्षेप में उल्लेख कर चुके हैं। जो सॉकेट इन ट्रांसपोर्ट प्रोटोकॉल में से किसी एक का उपयोग करते हैं, उन्हें UDP या TCP सॉकेट कहा जाता है।
IPC सॉकेट
नेटवर्क सॉकेटों के अलावा अन्य प्रकार भी होते हैं। उदाहरण के लिए, IPC (Inter Process Communication) सॉकेट। IPC सॉकेट एक ही मशीन पर प्रक्रियाओं के बीच डेटा ट्रांसफर करने के लिए बने हैं, जबकि नेटवर्क सॉकेट यही काम नेटवर्क के पार कर सकते हैं।
IPC सॉकेट का अच्छा पहलू यह है कि वे पैकेट तैयार करने और डेटा भेजने के लिए रूट खोजने जैसे बहुत से ओवरहेड से बच जाते हैं। चूँकि IPC के संदर्भ में प्रेषक और प्राप्तकर्ता स्थानीय प्रक्रियाएँ होती हैं, IPC सॉकेट से संचार में आमतौर पर लेटेंसी कम होती है।
Unix‑सॉकेट
IPC सॉकेट का अच्छा उदाहरण Unix‑सॉकेट हैं, जो, Unix की परंपरा के अनुरूप, फ़ाइल सिस्टम पर बस फ़ाइलें ही होती हैं। उनकी पहचान IP पते और पोर्ट से नहीं, बल्कि फ़ाइल सिस्टम पर फ़ाइल पथ से होती है।
IPC के रूप में नेटवर्क सॉकेट
ध्यान दें कि आप इंटर-प्रोसेस कम्युनिकेशन के लिए नेटवर्क सॉकेट का भी उतना ही उपयोग कर सकते हैं यदि सर्वर और रिसीवर दोनों localhost पर हों (अर्थात, IP पता 127.0.0.1 हो)।
बेशक, एक ओर यह अतिरिक्त लेटेंसी जोड़ता है क्योंकि आपका डेटा नेटवर्क स्टैक द्वारा प्रोसेस किया जाता है; लेकिन दूसरी ओर, इससे हमें आधारभूत ऑपरेटिंग सिस्टम की चिंता नहीं करनी पड़ती, क्योंकि नेटवर्क सॉकेट सभी सिस्टमों पर मौजूद और काम करते हैं, जबकि IPC सॉकेट किसी विशिष्ट OS या OS-परिवार तक सीमित हो सकते हैं।
Python सॉकेट लाइब्रेरी
Python में सॉकेट प्रोग्रामिंग के लिए हम आधिकारिक बिल्ट-इन Python सॉकेट लाइब्रेरी का उपयोग करते हैं, जिसमें फ़ंक्शन, कॉन्स्टेंट और क्लास शामिल हैं—जो सॉकेट बनाने, प्रबंधित करने और उनके साथ काम करने के लिए उपयोग होते हैं। इस लाइब्रेरी के कुछ सामान्य फ़ंक्शन हैं:
- socket(): नया सॉकेट बनाता है।
- bind(): सॉकेट को किसी विशेष पते और पोर्ट से जोड़ता है।
- listen(): सॉकेट पर इनकमिंग कनेक्शनों को सुनना शुरू करता है।
- accept(): किसी क्लाइंट से कनेक्शन स्वीकार करता है और संचार के लिए नया सॉकेट लौटाता है।
- connect(): रिमोट सर्वर से कनेक्शन स्थापित करता है।
- send(): सॉकेट के माध्यम से डेटा भेजता है।
- recv(): सॉकेट से डेटा प्राप्त करता है।
- close(): सॉकेट कनेक्शन बंद करता है।
Python सॉकेट उदाहरण
आइए Python में लिखे एक व्यावहारिक उदाहरण से सॉकेट प्रोग्रामिंग देखें। यहाँ हमारा लक्ष्य दो एप्लिकेशन को जोड़ना और उनमें आपसी संचार कराना है। हम Python सॉकेट लाइब्रेरी का उपयोग करके एक सर्वर सॉकेट एप्लिकेशन बनाएँगे, जो नेटवर्क के पार किसी क्लाइंट के साथ संचार और सूचना का आदान–प्रदान करेगा।
विचारणीय बातें और सीमाएँ
ध्यान दें कि शैक्षिक उद्देश्यों के लिए हमारा उदाहरण सरलीकृत है, और एप्लिकेशन स्थानीय रूप से चलेंगे तथा वास्तविक नेटवर्क पर बात नहीं करेंगे—हम क्लाइंट को सर्वर से जोड़ने के लिए लूपबैक localhost पता उपयोग करेंगे।
इसका अर्थ है कि क्लाइंट और सर्वर दोनों एक ही मशीन पर चलेंगे, और क्लाइंट उसी मशीन से कनेक्शन शुरू करेगा जिस पर वह चल रहा है—हालाँकि एक अलग प्रक्रिया से, जो सर्वर का प्रतिनिधित्व करती है।
भिन्न मशीनों पर चलाना
वैकल्पिक रूप से, आप अपने एप्लिकेशन दो अलग डिवाइसों पर रख सकते हैं और दोनों को एक ही Wi‑Fi राउटर से जोड़ सकते हैं, जो एक लोकल एरिया नेटवर्क बनाएगा। तब एक डिवाइस पर चल रहा क्लाइंट, दूसरे पर चल रहे सर्वर से कनेक्ट हो सकता है।
इस स्थिति में, आपको अपने राउटर द्वारा डिवाइसों को सौंपे गए IP पते जानने होंगे और localhost (127.0.0.1) लूपबैक IP की जगह उनका उपयोग करना होगा (IP पते देखने के लिए Unix‑like सिस्टम पर ifconfig टर्मिनल कमांड या Windows पर ipconfig उपयोग करें)। अपने एप्लिकेशन के IP पते प्राप्त करने के बाद, आप उन्हें कोड में तदनुसार बदल दें, और उदाहरण फिर भी काम करेगा।
Python में सॉकेट सर्वर बनाना
आइए सर्वर सॉकेट बनाकर शुरू करें (खासतौर पर Python TCP सर्वर, क्योंकि यह TCP सॉकेट के साथ काम करेगा—जैसा हम देखेंगे), जो क्लाइंटों के साथ संदेशों का आदान–प्रदान करेगा।
तो, नीचे दिए गए चरणों का पालन करें:
थोड़े बोइलरप्लेट के साथ Python फ़ाइल बनाना
-
server.pyनाम की फ़ाइल बनाएं -
अपने Python स्क्रिप्ट में
socketमॉड्यूल इम्पोर्ट करें।
import socket
run_serverनाम का एक फ़ंक्शन जोड़ें। हम अपना अधिकांश कोड यहीं जोड़ेंगे। जब आप फ़ंक्शन में कोड जोड़ें, तो सही इंडेंटेशन करना न भूलें:
def run_server():
# your code will go here
सॉकेट ऑब्जेक्ट इंस्टैंशिएट करना
अगले चरण में, run_server में, socket.socket() फ़ंक्शन का उपयोग करके एक सॉकेट ऑब्जेक्ट बनाएं।
पहला आर्ग्युमेंट (socket.AF_INET) IPv4 के लिए IP एड्रेस फैमिली निर्दिष्ट करता है (अन्य विकल्प: IPv6 के लिए AF_INET6 और Unix‑सॉकेट के लिए AF_UNIX)
दूसरा आर्ग्युमेंट (socket.SOCK_STREAM) इंगित करता है कि हम TCP सॉकेट का उपयोग कर रहे हैं।
TCP का उपयोग करने पर ऑपरेटिंग सिस्टम इन-ऑर्डर डेटा डिलीवरी, त्रुटि-पहचान और पुन:प्रेषण, और फ्लो कंट्रोल के साथ एक विश्वसनीय कनेक्शन बनाता है। आपको इन सभी विवरणों को लागू करने के बारे में नहीं सोचना पड़ता।
UDP सॉकेट निर्दिष्ट करने का एक विकल्प भी है: socket.SOCK_DGRAM। यह ऐसा सॉकेट बनाएगा जो अंदरूनी तौर पर UDP की सभी विशेषताएँ लागू करता है।
यदि आप इससे भी अधिक लो-लेवल जाना चाहते हैं और TCP/IP नेटवर्क लेयर प्रोटोकॉल (जिसका सॉकेट उपयोग करते हैं) के ऊपर अपना स्वयं का ट्रांसपोर्ट लेयर प्रोटोकॉल बनाना चाहते हैं, तो दूसरे आर्ग्युमेंट के लिए socket.SOCK_RAW मान का उपयोग कर सकते हैं। इस स्थिति में ऑपरेटिंग सिस्टम आपके लिए कोई उच्च-स्तरीय प्रोटोकॉल विशेषता नहीं संभालेगा और यदि ज़रूरत हो, तो आपको सभी हेडर, कनेक्शन कन्फर्मेशन और रिट्रांसमिशन फ़ंक्शनलिटी स्वयं लागू करनी होगी। अन्य मान भी हैं जिनके बारे में आप डॉक्यूमेंटेशन में पढ़ सकते हैं।
# create a socket object
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
सर्वर सॉकेट को IP पता और पोर्ट से बाँधना
होस्टनेम या सर्वर IP और पोर्ट परिभाषित करें ताकि वह पता तय हो जाए जिससे सर्वर सुलभ होगा और जहाँ वह इनकमिंग कनेक्शनों को सुनेगा। इस उदाहरण में सर्वर स्थानीय मशीन पर सुन रहा है—यह server_ip वेरिएबल को 127.0.0.1 (localhost) सेट करने से निर्धारित होता है।
port वेरिएबल 8000 पर सेट है—यह वह पोर्ट नंबर है जिससे ऑपरेटिंग सिस्टम सर्वर एप्लिकेशन की पहचान करेगा (सिस्टम प्रक्रियाओं द्वारा उपयोग किए जाने वाले पोर्ट से टकराव से बचने के लिए 1023 से ऊपर के मानों का उपयोग करना अनुशंसित है)।
server_ip = "127.0.0.1"
port = 8000
पहले परिभाषित IP पते और पोर्ट से सॉकेट को बाँधकर, कनेक्शन प्राप्त करने के लिए सॉकेट को तैयार करें।
# bind the socket to a specific address and port
server.bind((server_ip, port))
इनकमिंग कनेक्शनों को सुनना
listen फ़ंक्शन से सर्वर सॉकेट को listening अवस्था में रखें। इसका backlog आर्ग्युमेंट यह सेट करता है कि स्वीकार किए जाने से पहले कतार में कितने इनकमिंग कनेक्शन बैठ सकते हैं।
अपने उदाहरण में हम 0 पास करते हैं, जो अधिकांश सिस्टमों पर प्रभावी रूप से सर्वर को एक समय में एक क्लाइंट तक सीमित करता है—जब तक वह व्यस्त है, अतिरिक्त कनेक्शन प्रयास अस्वीकार हो जाते हैं। अधिक मान (जैसे 1 या अधिक) उतने क्लाइंटों को कतार में प्रतीक्षा करने देता है; एक क्लाइंट पर accept कॉल होते ही वह कतार से निकल जाता है और स्लॉट खाली हो जाता है।
यदि आप आर्ग्युमेंट छोड़ते हैं, तो यह सिस्टम डिफ़ॉल्ट पर लौटता है (Unix पर, /proc/sys/net/core/somaxconn में देखा जा सकता है)।
# listen for incoming connections
server.listen(0)
print(f"Listening on {server_ip}:{port}")
इनकमिंग कनेक्शनों को स्वीकार करना
अब, क्लाइंट कनेक्शनों की प्रतीक्षा करें और उन्हें स्वीकार करें। accept मेथड, तब तक निष्पादन थ्रेड को रोक देता है जब तक कोई क्लाइंट कनेक्ट नहीं होता। फिर यह (conn, address) की एक टपल लौटाता है, जहाँ address क्लाइंट के IP पते और पोर्ट की टपल होती है, और conn एक नया सॉकेट ऑब्जेक्ट होता है जो क्लाइंट के साथ कनेक्शन साझा करता है और उसी से संवाद करने में इस्तेमाल किया जा सकता है।
accept नया सॉकेट बनाता है ताकि क्लाइंट से संचार किया जा सके, बजाय इसके कि listening सॉकेट (हमारे उदाहरण में server) को क्लाइंट के पते से बाँधकर उसी से संचार किया जाए, क्योंकि listening सॉकेट को अन्य क्लाइंटों से आगे के कनेक्शनों को सुनना होता है, अन्यथा वह ब्लॉक हो जाएगा। बेशक, हमारे मामले में हम एक समय में केवल एक ही क्लाइंट संभालते हैं और बाकी सभी कनेक्शनों को इस दौरान अस्वीकार करते हैं, पर यह तब और प्रासंगिक होगा जब हम मल्टीथ्रेडेड सर्वर के उदाहरण पर आएँगे।
# accept incoming connections
client_socket, client_address = server.accept()
print(f"Accepted connection from {client_address[0]}:{client_address[1]}")
कम्युनिकेशन लूप बनाना
जैसे ही क्लाइंट के साथ कनेक्शन स्थापित हो जाता है (accept कॉल के बाद), हम संचार के लिए एक अनंत लूप शुरू करते हैं। इस लूप में, हम client_socket ऑब्जेक्ट के recv मेथड को कॉल करते हैं। यह मेथड क्लाइंट से निर्दिष्ट बाइट्स की संख्या प्राप्त करता है—हमारे मामले में 1024।
1024 बाइट्स पेलोड साइज के लिए बस एक सामान्य परंपरा है, क्योंकि यह दो का घात है, जो किसी मनमाने मान की तुलना में अनुकूलन हेतु बेहतर हो सकता है। हालाँकि आप चाहें तो इस मान को बदल सकते हैं।
क्योंकि क्लाइंट से request वेरिएबल में प्राप्त डेटा रॉ बाइनरी रूप में होता है, हमने उसे decode फ़ंक्शन का उपयोग करके बाइट्स के अनुक्रम से स्ट्रिंग में बदला।
फिर एक if स्टेटमेंट है, जो हमें ”close” संदेश मिलने पर कम्युनिकेशन लूप से बाहर निकल जाता है। अर्थात, जैसे ही हमारा सर्वर को ”close” स्ट्रिंग रिक्वेस्ट में मिलती है, वह क्लाइंट को कन्फर्मेशन भेजता है और उसका कनेक्शन समाप्त कर देता है। अन्यथा, हम प्राप्त संदेश को कंसोल में प्रिंट करते हैं। हमारे मामले में कन्फर्मेशन बस ”closed” स्ट्रिंग क्लाइंट को भेजना है।
ध्यान दें कि if स्टेटमेंट में request स्ट्रिंग पर उपयोग किया गया lower मेथड, उसे लोअरकेस में बदल देता है। इस तरह हमें फ़र्क नहीं पड़ता कि close स्ट्रिंग मूल रूप से अपरकेस में लिखी गई थी या लोअरकेस में।
# receive data from the client
while True:
request = client_socket.recv(1024)
request = request.decode("utf-8") # convert bytes to string
# if we receive "close" from the client, then we break
# out of the loop and close the connection
if request.lower() == "close":
# send response to the client which acknowledges that the
# connection should be closed and break out of the loop
client_socket.send("closed".encode("utf-8"))
break
print(f"Received: {request}")
क्लाइंट को उत्तर वापस भेजना
अब हमें सर्वर का सामान्य उत्तर संभालना चाहिए (जब क्लाइंट कनेक्शन बंद करना नहीं चाहता)। while लूप के अंदर, ठीक print(f"Received: {request}") के बाद, निम्न पंक्तियाँ जोड़ें, जो प्रतिक्रिया स्ट्रिंग (”accepted” हमारे मामले में) को बाइट्स में बदलेंगी और क्लाइंट को भेजेंगी। इस तरह जब भी सर्वर को क्लाइंट से ”close” के अलावा कोई संदेश मिलेगा, वह उत्तर में ”accepted” स्ट्रिंग भेज देगा:
response = "accepted".encode("utf-8") # convert string to bytes
# convert and send accept response to the client
client_socket.send(response)
संसाधन मुक्त करना
एक बार जब हम अनंत while लूप से बाहर आ जाते हैं, तो क्लाइंट के साथ संचार पूरा हो चुका होता है, इसलिए हम close मेथड का उपयोग करके क्लाइंट सॉकेट बंद करते हैं ताकि सिस्टम संसाधन मुक्त हो जाएँ। हम सर्वर सॉकेट भी उसी मेथड से बंद करते हैं, जिससे हमारा सर्वर प्रभावी रूप से शटडाउन हो जाता है। वास्तविक दुनिया के परिदृश्य में, हम निश्चित रूप से चाहेंगे कि सर्वर अन्य क्लाइंटों को सुनना जारी रखे और केवल एक से संवाद करने के बाद बंद न हो जाए—लेकिन चिंता न करें, हम आगे एक और उदाहरण देखेंगे।
फिलहाल, अनंत while लूप के बाद ये पंक्तियाँ जोड़ें:
# close connection socket with the client
client_socket.close()
print("Connection to client closed")
# close server socket
server.close()
ध्यान दें: अपनी server.py फ़ाइल के अंत में run_server फ़ंक्शन को कॉल करना न भूलें। बस निम्न कोड पंक्ति का उपयोग करें:
run_server()
पूर्ण सर्वर सॉकेट कोड उदाहरण
यह रहा server.py का पूर्ण सोर्स कोड:
import socket
def run_server():
# create a socket object
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_ip = "127.0.0.1"
port = 8000
# bind the socket to a specific address and port
server.bind((server_ip, port))
# listen for incoming connections
server.listen(0)
print(f"Listening on {server_ip}:{port}")
# accept incoming connections
client_socket, client_address = server.accept()
print(f"Accepted connection from {client_address[0]}:{client_address[1]}")
# receive data from the client
while True:
request = client_socket.recv(1024)
request = request.decode("utf-8") # convert bytes to string
# if we receive "close" from the client, then we break
# out of the loop and close the conneciton
if request.lower() == "close":
# send response to the client which acknowledges that the
# connection should be closed and break out of the loop
client_socket.send("closed".encode("utf-8"))
break
print(f"Received: {request}")
response = "accepted".encode("utf-8") # convert string to bytes
# convert and send accept response to the client
client_socket.send(response)
# close connection socket with the client
client_socket.close()
print("Connection to client closed")
# close server socket
server.close()
run_server()
ध्यान दें कि इस बुनियादी उदाहरण को उलझाने और जटिल बनाने से बचने के लिए हमने एरर हैंडलिंग छोड़ दी है। आप निश्चित रूप से try-except ब्लॉक जोड़ना चाहेंगे और सुनिश्चित करेंगे कि आप हमेशा finally क्लॉज़ में सॉकेट बंद करें। आगे पढ़ें और हम एक अधिक उन्नत उदाहरण देखेंगे।
Python में क्लाइंट सॉकेट बनाना
सर्वर सेटअप करने के बाद, अगला चरण ऐसा क्लाइंट सेटअप करना है जो आपके सर्वर से कनेक्ट हो और अनुरोध भेजे। तो, नीचे दिए गए चरणों से शुरू करते हैं:
थोड़े बोइलरप्लेट के साथ Python फ़ाइल बनाना
client.pyनाम की नई फ़ाइल बनाएं- सॉकेट लाइब्रेरी इम्पोर्ट करें:
import socket
run_clientफ़ंक्शन परिभाषित करें, जहाँ हम अपना सारा कोड रखेंगे:
def run_client():
# your code will go here
सॉकेट ऑब्जेक्ट इंस्टैंशिएट करना
अगला, socket.socket() फ़ंक्शन का उपयोग करके एक TCP सॉकेट ऑब्जेक्ट बनाएं, जो क्लाइंट का सर्वर से संपर्क बिंदु होगा।
# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
सर्वर सॉकेट से कनेक्ट करना
सर्वर का IP पता और पोर्ट निर्दिष्ट करें ताकि उससे कनेक्ट हो सकें। ये वही होने चाहिए जो आपने पहले server.py में सेट किए थे।
server_ip = "127.0.0.1" # replace with the server's IP address
server_port = 8000 # replace with the server's port number
क्लाइंट सॉकेट ऑब्जेक्ट पर connect मेथड का उपयोग करके सर्वर से कनेक्शन स्थापित करें। ध्यान दें कि हमने क्लाइंट सॉकेट को किसी IP पते या पोर्ट से बाइंड नहीं किया। यह क्लाइंट के लिए सामान्य है, क्योंकि connect स्वतः ही एक फ्री पोर्ट चुनेगा और सिस्टम के नेटवर्क इंटरफ़ेस में से सर्वर तक सर्वोत्तम रूट देने वाले IP पते (127.0.0.1 हमारे मामले में) को चुनकर क्लाइंट सॉकेट को उनसे बाइंड कर देगा।
# establish connection with server
client.connect((server_ip, server_port))
कम्युनिकेशन लूप बनाना
कनेक्शन स्थापित होने के बाद, हम सर्वर को कई संदेश भेजने के लिए एक अनंत कम्युनिकेशन लूप शुरू करते हैं। हम Python के बिल्ट-इन input फ़ंक्शन का उपयोग करके उपयोगकर्ता से इनपुट लेते हैं, फिर उसे बाइट्स में एन्कोड करते हैं और अधिकतम 1024 बाइट तक ट्रिम करते हैं। उसके बाद client.send का उपयोग करके संदेश सर्वर को भेजते हैं।
while True:
# input message and send it to the server
msg = input("Enter message: ")
client.send(msg.encode("utf-8")[:1024])
सर्वर के उत्तर को संभालना
जैसे ही सर्वर क्लाइंट से संदेश प्राप्त करता है, वह उसका उत्तर देता है। अब, अपने क्लाइंट कोड में, हम सर्वर का उत्तर प्राप्त करना चाहते हैं। इसके लिए, कम्युनिकेशन लूप में, हम recv मेथड से अधिकतम 1024 बाइट पढ़ते हैं। फिर हम उत्तर को decode का उपयोग करके बाइट्स से स्ट्रिंग में बदलते हैं और जाँचते हैं कि क्या यह ”closed” के बराबर है। यदि ऐसा है, तो हम लूप से बाहर निकलते हैं, जो जैसा कि हम आगे देखेंगे, क्लाइंट का कनेक्शन समाप्त कर देगा। अन्यथा, हम सर्वर का उत्तर कंसोल में प्रिंट करते हैं।
# receive message from the server
response = client.recv(1024)
response = response.decode("utf-8")
# if server sent us "closed" in the payload, we break out of the loop and close our socket
if response.lower() == "closed":
break
print(f"Received: {response}")
संसाधन मुक्त करना
अंत में, while लूप के बाद, close मेथड का उपयोग करके क्लाइंट सॉकेट कनेक्शन बंद करें। इससे सुनिश्चित होता है कि संसाधन ठीक से मुक्त हो जाएँ और कनेक्शन समाप्त हो जाए (अर्थात जब हमें “closed” संदेश मिलता है और हम while लूप से बाहर निकलते हैं)।
# close client socket (connection to the server)
client.close()
print("Connection to server closed")
ध्यान दें: फिर से, फ़ाइल के अंत में ऊपर लागू किए गए run_client फ़ंक्शन को निम्न प्रकार से कॉल करना न भूलें:
run_client()
पूर्ण क्लाइंट सॉकेट कोड उदाहरण
यह रहा client.py का पूरा कोड:
import socket
def run_client():
# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_ip = "127.0.0.1" # replace with the server's IP address
server_port = 8000 # replace with the server's port number
# establish connection with server
client.connect((server_ip, server_port))
while True:
# input message and send it to the server
msg = input("Enter message: ")
client.send(msg.encode("utf-8")[:1024])
# receive message from the server
response = client.recv(1024)
response = response.decode("utf-8")
# if server sent us "closed" in the payload, we break out of the loop and close our socket
if response.lower() == "closed":
break
print(f"Received: {response}")
# close client socket (connection to the server)
client.close()
print("Connection to server closed")
run_client()
अपने क्लाइंट और सर्वर का परीक्षण करें
ऊपर लिखे सर्वर और क्लाइंट इम्प्लीमेंटेशन का परीक्षण करने के लिए निम्न करें:
- दो टर्मिनल विंडो एक साथ खोलें।
- एक टर्मिनल विंडो में, उस डायरेक्ट्री पर जाएँ जहाँ
server.pyफ़ाइल स्थित है और सर्वर शुरू करने के लिए निम्न कमांड चलाएँ:
python server.py
यह सर्वर सॉकेट को localhost एड्रेस (127.0.0.1) पर पोर्ट 8000 से बाँध देगा और इनकमिंग कनेक्शनों को सुनना शुरू करेगा।
- दूसरे टर्मिनल में, उस डायरेक्ट्री पर जाएँ जहाँ
client.pyफ़ाइल स्थित है और क्लाइंट शुरू करने के लिए निम्न कमांड चलाएँ:
python client.py
यह उपयोगकर्ता इनपुट के लिए प्रॉम्प्ट करेगा। फिर आप अपना संदेश टाइप कर Enter दबा सकते हैं। यह आपका इनपुट सर्वर को ट्रांसफ़र कर देगा और उसके टर्मिनल विंडो में दिखाएगा। सर्वर अपना उत्तर क्लाइंट को भेजेगा और क्लाइंट फिर से आपसे इनपुट मांगेगा। यह तब तक जारी रहेगा जब तक आप सर्वर को ”close” स्ट्रिंग नहीं भेजते।
एकाधिक क्लाइंट के साथ काम करना – मल्टीथ्रेडिंग
हमने पिछले उदाहरण में देखा कि सर्वर एकल क्लाइंट के अनुरोधों का कैसे उत्तर देता है, लेकिन कई व्यावहारिक परिस्थितियों में अनेक क्लाइंटों को एक साथ एक ही सर्वर से जुड़ना पड़ सकता है। यहीं मल्टीथ्रेडिंग काम आती है। मल्टीथ्रेडिंग का उपयोग तब होता है जब आपको एक साथ (कॉनकरेंटली) कई कार्य (जैसे कई फ़ंक्शन चलाना) संभालने हों।
विचार यह है कि एक थ्रेड स्पॉन किया जाए—जो निर्देशों का स्वतंत्र समूह होता है और प्रोसेसर द्वारा हैंडल किया जा सकता है। थ्रेड, प्रक्रियाओं की तुलना में कहीं अधिक हल्के होते हैं, क्योंकि वे वास्तव में किसी प्रक्रिया के भीतर ही रहते हैं और उनके लिए बहुत अधिक संसाधन आवंटित नहीं करने पड़ते।
Python में मल्टीथ्रेडिंग की सीमाएँ
डिफ़ॉल्ट CPython बिल्ड में, ग्लोबल इंटरप्रेटर लॉक (GIL) के कारण एक समय में केवल एक थ्रेड Python बाइटकोड चलाता है। सॉकेट प्रोग्रामिंग के लिए यह ठीक है—नेटवर्क I/O के दौरान GIL रिलीज़ हो जाता है, इसलिए थ्रेड वाकई में समानांतर कनेक्शनों पर प्रतीक्षा कर सकते हैं। Python 3.13 (अक्टूबर 2024) से, CPython एक फ्री‑थ्रेडेड बिल्ड (PEP 703) भी देता है जो GIL हटाता है, और asyncio उच्च‑कॉनकरेंसी सॉकेट कोड के लिए अधिक सामान्य आधुनिक विकल्प है।
मल्टीथ्रेडेड सर्वर उदाहरण
आइए नीचे दिए गए उदाहरण में देखें कि कैसे आप अपने सर्वर में मल्टीथ्रेडिंग जोड़कर बड़ी संख्या में क्लाइंट संभाल सकते हैं। ध्यान दें कि इस बार हम try‑except‑finally ब्लॉक का उपयोग करके कुछ बुनियादी एरर हैंडलिंग भी जोड़ेंगे। शुरू करने के लिए, नीचे दिए चरणों का पालन करें:
थ्रेड स्पॉन करने वाला सर्वर फ़ंक्शन बनाना
अपनी Python फ़ाइल में, सॉकेट और थ्रेड दोनों के साथ काम करने के लिए socket और threading मॉड्यूल इम्पोर्ट करें:
import socket
import threading
run_server फ़ंक्शन परिभाषित करें, जो ऊपर वाले उदाहरण की तरह ही सर्वर सॉकेट बनाएगा, उसे बाइंड करेगा और इनकमिंग कनेक्शनों को सुनेगा। फिर अनंत while लूप में accept कॉल करें। यह हमेशा नए कनेक्शनों के लिए सुनता रहेगा। accept को इनकमिंग कनेक्शन मिलता है और वह लौट आता है, तो threading.Thread कंस्ट्रक्टर से एक थ्रेड बनाएँ। यह थ्रेड handle_client फ़ंक्शन चलाएगा जिसे हम आगे परिभाषित करेंगे, और उसे आर्ग्युमेंट के रूप में client_socket और addr पास करें (addr टपल में कनेक्टेड क्लाइंट का IP पता और पोर्ट होता है)। थ्रेड बनने के बाद, उसके निष्पादन के लिए start कॉल करें।
याद रखें कि accept कॉल ब्लॉकिंग है, तो while लूप की पहली इटरेशन में, जब हम accept वाली पंक्ति पर पहुँचते हैं, तो हम रुकते हैं और क्लाइंट कनेक्शन की प्रतीक्षा करते हैं। जैसे ही क्लाइंट कनेक्ट होता है, accept मेथड लौट आता है, और हम निष्पादन जारी रखते हैं: एक थ्रेड स्पॉन करते हैं, जो उस क्लाइंट को संभालेगा, और फिर अगली इटरेशन में चले जाते हैं जहाँ हम फिर accept कॉल पर रुकेंगे, किसी अन्य क्लाइंट के कनेक्ट होने की प्रतीक्षा में।
फ़ंक्शन के अंत में, कुछ एरर हैंडलिंग है जो सुनिश्चित करती है कि यदि कुछ अप्रत्याशित होता है तो सर्वर सॉकेट हमेशा बंद हो जाए।
def run_server():
server_ip = "127.0.0.1" # server hostname or IP address
port = 8000 # server port number
# create a socket object
try:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to the host and port
server.bind((server_ip, port))
# listen for incoming connections
server.listen()
print(f"Listening on {server_ip}:{port}")
while True:
# accept a client connection
client_socket, addr = server.accept()
print(f"Accepted connection from {addr[0]}:{addr[1]}")
# start a new thread to handle the client
thread = threading.Thread(target=handle_client, args=(client_socket, addr,))
thread.start()
except Exception as e:
print(f"Error: {e}")
finally:
server.close()
ध्यान दें कि हमारे उदाहरण में सर्वर केवल अप्रत्याशित त्रुटि होने की स्थिति में ही रुकेगा। अन्यथा, वह अनिश्चितकाल तक क्लाइंटों को सुनेगा, और यदि आपको इसे रोकना हो, तो आपको टर्मिनल को ही किल करना पड़ेगा।
अलग थ्रेड में चलने वाला क्लाइंट‑हैंडलिंग फ़ंक्शन बनाना
अब, run_server फ़ंक्शन के ऊपर, handle_client नाम का एक और फ़ंक्शन परिभाषित करें। यह फ़ंक्शन प्रत्येक क्लाइंट कनेक्शन के लिए अलग थ्रेड में निष्पादित होगा। यह आर्ग्युमेंट के रूप में क्लाइंट का सॉकेट ऑब्जेक्ट और addr टपल लेता है।
इस फ़ंक्शन के भीतर, हम सिंगल‑थ्रेडेड उदाहरण जैसा ही करते हैं, साथ में कुछ एरर हैंडलिंग: हम recv का उपयोग करके क्लाइंट से संदेश प्राप्त करने के लिए एक लूप शुरू करते हैं।
फिर जाँचते हैं कि क्या हमें close संदेश मिला। यदि हाँ, तो हम ”closed” स्ट्रिंग से उत्तर देते हैं और लूप से बाहर निकलकर कनेक्शन बंद कर देते हैं। अन्यथा, हम क्लाइंट की रिक्वेस्ट स्ट्रिंग को कंसोल में प्रिंट करते हैं और अगला संदेश प्राप्त करने के लिए अगली इटरेशन में चले जाते हैं।
इस फ़ंक्शन के अंत में, अप्रत्याशित मामलों के लिए कुछ एरर हैंडलिंग (except क्लॉज़) है, और एक finally क्लॉज़ है जहाँ हम client_socket को close से रिलीज़ करते हैं। यह finally क्लॉज़ हर हाल में चलेगा, जिससे सुनिश्चित होता है कि क्लाइंट सॉकेट हमेशा सही तरह मुक्त हो।
def handle_client(client_socket, addr):
try:
while True:
# receive and print client messages
request = client_socket.recv(1024).decode("utf-8")
if request.lower() == "close":
client_socket.send("closed".encode("utf-8"))
break
print(f"Received: {request}")
# convert and send accept response to the client
response = "accepted"
client_socket.send(response.encode("utf-8"))
except Exception as e:
print(f"Error when handling client: {e}")
finally:
client_socket.close()
print(f"Connection to client ({addr[0]}:{addr[1]}) closed")
जब handle_client लौट आता है, तो उसे निष्पादित करने वाला थ्रेड भी स्वतः ही रिलीज़ हो जाएगा।
ध्यान दें: फ़ाइल के अंत में run_server फ़ंक्शन को कॉल करना न भूलें।
पूर्ण मल्टीथ्रेडेड सर्वर कोड उदाहरण
अब, मल्टीथ्रेडिंग सर्वर का पूरा कोड एक साथ रखते हैं:
import socket
import threading
def handle_client(client_socket, addr):
try:
while True:
# receive and print client messages
request = client_socket.recv(1024).decode("utf-8")
if request.lower() == "close":
client_socket.send("closed".encode("utf-8"))
break
print(f"Received: {request}")
# convert and send accept response to the client
response = "accepted"
client_socket.send(response.encode("utf-8"))
except Exception as e:
print(f"Error when hanlding client: {e}")
finally:
client_socket.close()
print(f"Connection to client ({addr[0]}:{addr[1]}) closed")
def run_server():
server_ip = "127.0.0.1" # server hostname or IP address
port = 8000 # server port number
# create a socket object
try:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to the host and port
server.bind((server_ip, port))
# listen for incoming connections
server.listen()
print(f"Listening on {server_ip}:{port}")
while True:
# accept a client connection
client_socket, addr = server.accept()
print(f"Accepted connection from {addr[0]}:{addr[1]}")
# start a new thread to handle the client
thread = threading.Thread(target=handle_client, args=(client_socket, addr,))
thread.start()
except Exception as e:
print(f"Error: {e}")
finally:
server.close()
run_server()
ध्यान दें: वास्तविक‑दुनिया के कोड में, संभावित समस्याओं जैसे रेस कंडिशन या डेटा असंगतता से बचने के लिए, मल्टीथ्रेडेड सर्वरों के साथ काम करते समय थ्रेड सेफ़्टी और सिंक्रोनाइज़ेशन तकनीकों पर विचार करना महत्वपूर्ण है। हमारे सरल उदाहरण में यह समस्या नहीं है।
बेसिक एरर हैंडलिंग के साथ क्लाइंट उदाहरण
अब जब हमारे पास ऐसा सर्वर इम्प्लीमेंटेशन है जो एक साथ कई क्लाइंट संभाल सकता है, तो हम कनेक्शन शुरू करने के लिए ऊपर दिए गए पहले बुनियादी उदाहरण जैसा ही क्लाइंट उपयोग कर सकते हैं, या हम उसे थोड़ा अपडेट कर कुछ एरर हैंडलिंग जोड़ सकते हैं। नीचे दिया कोड पिछले क्लाइंट उदाहरण के समान है, बस try‑except ब्लॉक जोड़ दिए गए हैं:
import socket
def run_client():
# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_ip = "127.0.0.1" # replace with the server's IP address
server_port = 8000 # replace with the server's port number
# establish connection with server
client.connect((server_ip, server_port))
try:
while True:
# get input message from user and send it to the server
msg = input("Enter message: ")
client.send(msg.encode("utf-8")[:1024])
# receive message from the server
response = client.recv(1024)
response = response.decode("utf-8")
# if server sent us "closed" in the payload, we break out of
# the loop and close our socket
if response.lower() == "closed":
break
print(f"Received: {response}")
except Exception as e:
print(f"Error: {e}")
finally:
# close client socket (connection to the server)
client.close()
print("Connection to server closed")
run_client()
मल्टीथ्रेडिंग उदाहरण का परीक्षण
यदि आप मल्टी‑क्लाइंट इम्प्लीमेंटेशन का परीक्षण करना चाहते हैं, तो क्लाइंटों के लिए कई टर्मिनल विंडो और सर्वर के लिए एक खोलें। पहले python server.py से सर्वर शुरू करें। उसके बाद python client.py से कुछ क्लाइंट शुरू करें। सर्वर की टर्मिनल विंडो में आप देखेंगे कि नए क्लाइंट सर्वर से कैसे कनेक्ट होते हैं। अब आप संबंधित टर्मिनलों में अलग‑अलग क्लाइंटों से संदेश भेज सकते हैं—ये सभी सर्वर साइड पर हैंडल होकर कंसोल में प्रिंट हो जाएँगे।
डेटा साइंस में सॉकेट प्रोग्रामिंग के उपयोग
यद्यपि हर नेटवर्क एप्लिकेशन अंदरूनी तौर पर OS द्वारा बनाए सॉकेट का उपयोग करता है, अनेक ऐसी प्रणालियाँ हैं जो विशेष उपयोग‑केस के लिए या प्रदर्शन सुधारने के लिए विशेष रूप से सॉकेट प्रोग्रामिंग पर अधिक निर्भर होती हैं। लेकिन डेटा साइंस के संदर्भ में सॉकेट प्रोग्रामिंग उपयोगी कैसे है? जब भी बहुत बड़े पैमाने पर डेटा को तेज़ी से प्राप्त या भेजने की ज़रूरत पड़ती है, यह निश्चित रूप से सार्थक भूमिका निभाती है। अतः सॉकेट प्रोग्रामिंग मुख्यतः डेटा कलेक्शन और रियल‑टाइम प्रोसेसिंग, डिस्ट्रिब्यूटेड कंप्यूटिंग और इंटर‑प्रोसेस कम्युनिकेशन में उपयोग होती है। आइए डेटा साइंस के क्षेत्र में कुछ विशिष्ट अनुप्रयोगों को करीब से देखें।
रियल‑टाइम डेटा कलेक्शन
सॉकेट का व्यापक उपयोग विभिन्न स्रोतों से रियल‑टाइम डेटा इकट्ठा करने के लिए होता है—आगे की प्रोसेसिंग, डेटाबेस में फॉरवर्ड करने या किसी एनालिटिक्स पाइपलाइन आदि के लिए। उदाहरण के लिए, किसी वित्तीय सिस्टम या सोशल मीडिया API से तुरंत डेटा प्राप्त करने के लिए सॉकेट का उपयोग किया जा सकता है, जिसे बाद में डेटा वैज्ञानिक प्रोसेस करें।
डिस्ट्रिब्यूटेड कंप्यूटिंग
डेटा वैज्ञानिक सॉकेट कनेक्टिविटी का उपयोग करके विशाल डेटा सेट के प्रोसेस और कंप्यूटेशन को कई मशीनों में बाँट सकते हैं। Apache Spark और अन्य डिस्ट्रिब्यूटेड कंप्यूटिंग फ्रेमवर्क में नोडों के बीच संचार हेतु सॉकेट प्रोग्रामिंग सामान्य है।
मॉडल डिप्लॉयमेंट
जब मशीन लर्निंग मॉडल उपयोगकर्ताओं को सर्व करने हों, तब सॉकेट प्रोग्रामिंग का उपयोग किया जा सकता है, जो भविष्यवाणियाँ और सुझाव तुरंत डिलीवर करने में सहायक है। रियल‑टाइम निर्णय‑निर्माण को सुगम बनाने के लिए, डेटा वैज्ञानिक उच्च‑प्रदर्शन सॉकेट‑आधारित सर्वर एप्लिकेशन का उपयोग कर सकते हैं—जो बड़े पैमाने पर डेटा लेते हैं, प्रशिक्षित मॉडलों से उसे प्रोसेस कर प्रेडिक्शन देते हैं, और फिर निष्कर्षों को तेज़ी से क्लाइंट को लौटा देते हैं।
इंटर‑प्रोसेस कम्युनिकेशन (IPC)
सॉकेट IPC के लिए उपयोग किए जा सकते हैं, जिससे एक ही मशीन पर चल रही विभिन्न प्रक्रियाएँ एक-दूसरे से संवाद कर सकें और डेटा का आदान‑प्रदान कर सकें। डेटा साइंस में यह जटिल और संसाधन‑सघन कंप्यूटेशन को कई प्रक्रियाओं में बाँटने में उपयोगी है। वास्तव में, Python की subprocessing लाइब्रेरी अक्सर इसी उद्देश्य से उपयोग होती है: यह कई प्रक्रियाएँ स्पॉन करती है ताकि एकाधिक प्रोसेसर कोर का उपयोग कर भारी गणनाओं के समय एप्लिकेशन प्रदर्शन बढ़ाया जा सके। ऐसी प्रक्रियाओं के बीच संचार IPC सॉकेट के माध्यम से लागू किया जा सकता है।
कोलैबोरेशन और कम्युनिकेशन
सॉकेट प्रोग्रामिंग डेटा वैज्ञानिकों के बीच रियल‑टाइम संचार और सहयोग संभव बनाती है। प्रभावी सहयोग और ज्ञान‑साझाकरण को सुगम बनाने के लिए सॉकेट‑आधारित चैट ऐप या कोलैबोरेटिव डेटा एनालिसिस प्लेटफ़ॉर्म उपयोग होते हैं।
यह उल्लेखनीय है कि उपर्युक्त कई अनुप्रयोगों में, डेटा वैज्ञानिक सीधे सॉकेट के साथ काम न भी करें। वे आमतौर पर ऐसी लाइब्रेरी, फ्रेमवर्क और सिस्टम उपयोग करते हैं, जो सॉकेट प्रोग्रामिंग की सभी लो‑लेवल बारीकियाँ छिपा देते हैं। हालाँकि, अंदरूनी तौर पर ऐसी सभी समाधानों का आधार सॉकेट संचार है और वे सॉकेट प्रोग्रामिंग का उपयोग करते हैं।
सॉकेट प्रोग्रामिंग की चुनौतियाँ और सर्वोत्तम अभ्यास
चूँकि सॉकेट कनेक्शनों के प्रबंधन की लो‑लेवल अवधारणा हैं, उनके साथ काम करने वाले डेवलपरों को मजबूत और विश्वसनीय एप्लिकेशन बनाने के लिए आवश्यक समस्त अवसंरचना को लागू करना पड़ता है। यह स्वाभाविक रूप से कई चुनौतियों के साथ आता है। हालाँकि, कुछ सर्वोत्तम अभ्यास और सामान्य दिशानिर्देश हैं, जिनका पालन करने से इन मुद्दों से निपटा जा सकता है। नीचे सॉकेट प्रोग्रामिंग में अक्सर सामने आने वाली समस्याएँ और उनके साथ कुछ सामान्य सुझाव दिए गए हैं:
कनेक्शन प्रबंधन
एक समय में कई कनेक्शनों के साथ काम करना—कई क्लाइंटों का प्रबंधन करना, और समवर्ती अनुरोधों को कुशलतापूर्वक संभालना—निश्चित रूप से चुनौतीपूर्ण और गैर‑तुल्य कार्य है। बॉटलनेक से बचने के लिए सावधानीपूर्वक संसाधन प्रबंधन और समन्वय की आवश्यकता होती है।
सर्वोत्तम अभ्यास
- सक्रिय कनेक्शनों का ट्रैक रखने के लिए सूची या शब्दकोश जैसी डेटा संरचनाओं का उपयोग करें। या स्केलेबिलिटी में मदद करने वाली कनेक्शन पूलिंग जैसी उन्नत तकनीकों का उपयोग करें।
- एक ही समय में कई क्लाइंट कनेक्शनों को संभालने के लिए थ्रेडिंग या असिंक्रोनस प्रोग्रामिंग तकनीकों का उपयोग करें।
- संसाधन मुक्त करने और मेमोरी लीकेज से बचने के लिए कनेक्शनों को सही ढंग से बंद करें।
त्रुटि प्रबंधन
कनेक्शन विफलताओं, टाइमआउट, और डेटा ट्रांसमिशन समस्याओं जैसी त्रुटियों से निपटना महत्वपूर्ण है। लो‑लेवल सॉकेट प्रोग्रामिंग करते समय इन त्रुटियों को संभालना और क्लाइंटों को उपयुक्त फीडबैक देना चुनौतीपूर्ण हो सकता है।
सर्वोत्तम अभ्यास
- विशिष्ट प्रकार की त्रुटियों को पकड़ने और संभालने के लिए try‑except‑finally ब्लॉक का उपयोग करें।
- सूचनात्मक एरर संदेश दें और ट्रबलशूटिंग में सहायता के लिए लॉगिंग का उपयोग करने पर विचार करें।
स्केलेबिलिटी और प्रदर्शन
उच्च‑वॉल्यूम डेटा स्ट्रीम या रियल‑टाइम एप्लिकेशन से निपटते समय, इष्टतम प्रदर्शन सुनिश्चित करना और लेटेंसी को न्यूनतम रखना प्रमुख चिंताएँ हैं।
सर्वोत्तम अभ्यास
- अनावश्यक डेटा प्रोसेसिंग और नेटवर्क ओवरहेड को न्यूनतम करके अपने कोड का प्रदर्शन अनुकूलित करें।
- बड़े डेटा ट्रांसफर को कुशलतापूर्वक संभालने के लिए बफ़रिंग तकनीकें लागू करें।
- क्लाइंट अनुरोधों को कई सर्वर इंस्टेंसों में बाँटने के लिए लोड बैलेंसिंग तकनीकों पर विचार करें।
सुरक्षा और प्रमाणीकरण
सॉकेट‑आधारित संचार को सुरक्षित बनाना और उचित प्रमाणीकरण तंत्र लागू करना कठिन हो सकता है। डेटा प्राइवेसी सुनिश्चित करना, अनधिकृत पहुँच को रोकना और दुर्भावनापूर्ण गतिविधियों से सुरक्षा देना—इनके लिए सुरक्षित प्रोटोकॉल का सावधानीपूर्वक चयन और कार्यान्वयन आवश्यक है।
सर्वोत्तम अभ्यास
- SSL/TLS सुरक्षा प्रोटोकॉल का उपयोग करें ताकि सूचना को एन्क्रिप्ट करके सुरक्षित डेटा ट्रांसमिशन सुनिश्चित हो।
- टोकन‑आधारित प्रमाणीकरण, पब्लिक‑की क्रिप्टोग्राफी, या यूज़रनेम/पासवर्ड जैसे सुरक्षित प्रमाणीकरण तरीकों से क्लाइंट पहचान सुनिश्चित करें।
- पासवर्ड या API कीज़ जैसी गोपनीय सूचनाएँ सुरक्षित रहें—उन्हें एन्क्रिप्ट रखें या आदर्शतः संग्रहीत ही न करें (यदि आवश्यक हो तो केवल उनके हैश)।
नेटवर्क विश्वसनीयता और रेज़िलिएंस
नेटवर्क रुकावटें, उतार‑चढ़ाव वाली बैंडविड्थ, और अविश्वसनीय कनेक्शन चुनौतियाँ खड़ी कर सकते हैं। स्थिर कनेक्शन बनाए रखना, डिस्कनेक्शनों को गरिमापूर्वक संभालना, और री‑कनेक्शन तंत्र लागू करना—मजबूत नेटवर्कड एप्लिकेशन के लिए आवश्यक है।
सर्वोत्तम अभ्यास
- निष्क्रिय या ड्रॉप्ड कनेक्शनों का पता लगाने के लिए keep‑alive संदेशों का उपयोग करें।
- अनिश्चितकालीन ब्लॉकिंग से बचने और समय पर उत्तर‑प्रसंस्करण सुनिश्चित करने के लिए टाइमआउट लागू करें।
- यदि कनेक्शन टूट जाए, तो उसे फिर से स्थापित करने के लिए एक्सपोनेंशियल बैकऑफ़ री‑कनेक्शन लॉजिक लागू करें।
कोड मेंटेनबिलिटी
अंत में, लेकिन कम महत्वपूर्ण नहीं—कोड मेंटेनबिलिटी। सॉकेट प्रोग्रामिंग की लो‑लेवल प्रकृति के कारण, डेवलपर अधिक कोड लिखते पाए जाते हैं। यह जल्दी ही अनियंत्रित स्पेगेटी कोड में बदल सकता है, इसलिए जितना जल्दी हो सके, कोड को व्यवस्थित और संरचित करना, और आर्किटेक्चर की योजना पर अतिरिक्त ध्यान देना आवश्यक है।
सर्वोत्तम अभ्यास
- अपने कोड को क्लासों या फ़ंक्शनों में बाँटें—जो आदर्श रूप से बहुत लंबे न हों।
- अपने क्लाइंट और सर्वर इम्प्लीमेंटेशन को मॉक कर, जल्दी ही यूनिट टेस्ट लिखें।
- जब तक बिल्कुल आवश्यक न हो, सॉकेट प्रोग्रामिंग की जगह कनेक्शनों से निपटने के लिए अधिक उच्च‑स्तरीय लाइब्रेरी उपयोग करने पर विचार करें।
समापन: Python में सॉकेट प्रोग्रामिंग
सॉकेट सभी नेटवर्क एप्लिकेशन का अभिन्न हिस्सा हैं। इस लेख में, हमने Python में सॉकेट प्रोग्रामिंग को देखा। याद रखने योग्य मुख्य बिंदु:
- सॉकेट ऐसे इंटरफ़ेस हैं जो कनेक्शन प्रबंधन का एब्स्ट्रैक्शन प्रदान करते हैं।
- सॉकेट विभिन्न प्रक्रियाओं (आमतौर पर क्लाइंट और सर्वर) के बीच, स्थानीय रूप से या नेटवर्क के पार, संचार सक्षम करते हैं।
- Python में, सॉकेट के साथ काम
socketलाइब्रेरी के माध्यम से होता है, जो अन्य बातों के अलावा,recv,send,listen,closeजैसे विभिन्न मेथड के साथ सॉकेट ऑब्जेक्ट प्रदान करती है। - सॉकेट प्रोग्रामिंग के डेटा साइंस में कई उपयोग हैं—जैसे डेटा कलेक्शन, इंटर‑प्रोसेस कम्युनिकेशन, और डिस्ट्रिब्यूटेड कंप्यूटिंग।
- सॉकेट प्रोग्रामिंग में चुनौतियाँ शामिल हैं—कनेक्शन प्रबंधन, डेटा अखंडता, स्केलेबिलिटी, एरर हैंडलिंग, सुरक्षा, और कोड मेंटेनबिलिटी।
सॉकेट प्रोग्रामिंग कौशल के साथ, डेवलपर कुशल, रियल‑टाइम नेटवर्क एप्लिकेशन बना सकते हैं। अवधारणाओं और सर्वोत्तम अभ्यासों में निपुण होकर, वे विश्वसनीय और स्केलेबल समाधान विकसित करने के लिए सॉकेट प्रोग्रामिंग की पूरी क्षमता का उपयोग कर सकते हैं।
हालाँकि, सॉकेट प्रोग्रामिंग एक बहुत लो‑लेवल तकनीक है, जिसका उपयोग कठिन होता है, क्योंकि एप्लिकेशन इंजीनियरों को एप्लिकेशन कम्युनिकेशन के हर छोटे‑से‑छोटे विवरण का ध्यान रखना पड़ता है।
आजकल, अक्सर हमें सीधे सॉकेट के साथ काम करने की ज़रूरत नहीं पड़ती, क्योंकि उन्हें आमतौर पर उच्च‑स्तरीय लाइब्रेरी और फ्रेमवर्क संभाल लेते हैं—जब तक कि एप्लिकेशन से अधिकतम प्रदर्शन न निचोड़ना हो या उसे व्यापक रूप से स्केल न करना हो।
फिर भी, सॉकेट को समझना और अंदरूनी तौर पर चीज़ें कैसे काम करती हैं, इसकी जानकारी रखना, आपको एक बेहतर डेवलपर या डेटा साइंटिस्ट बनाता है और हमेशा उपयोगी होता है।
Python की नेटवर्क एनालिसिस में भूमिका के बारे में और जानने के लिए हमारा Intermediate Network Analysis in Python कोर्स देखें। आप अपना Python प्रोग्रामिंग कौशल सुधारने के लिए हमारा Python Programming स्किल ट्रैक भी फॉलो कर सकते हैं।

सेरही एक सॉफ्टवेयर इंजीनियर हैं जिनके पास मुख्यतः बैकएंड तकनीकों—जैसे DBMS, डेटाबेस-विशिष्ट भाषाएं, Python, Node.js आदि—में 3 वर्षों का अनुभव है। उन्हें VueJS और ReactJS जैसे फ्रंटएंड फ़्रेमवर्क का भी अनुभव है।
FAQs
Python में सॉकेट प्रोग्रामिंग का उपयोग किस लिए होता है?
Python में सॉकेट प्रोग्रामिंग एप्लिकेशन को नेटवर्क पर या स्थानीय प्रक्रियाओं के बीच डेटा का आदान–प्रदान करने देती है। सामान्य उपयोगों में चैट ऐप्स, मल्टीप्लेयर गेम्स, IoT कम्युनिकेशन, डिस्ट्रिब्यूटेड कंप्यूटिंग, और मशीन लर्निंग मॉडलों को सर्व करना शामिल हैं। बिल्ट‑इन socket लाइब्रेरी क्लाइंट और सर्वर दोनों को संभालती है।
Python में TCP और UDP सॉकेट में क्या अंतर है?
TCP सॉकेट (socket.SOCK_STREAM) भरोसेमंद, क्रमबद्ध डिलीवरी और एरर जाँच प्रदान करते हैं—चैट ऐप्स, फ़ाइल ट्रांसफ़र और वेब सर्वरों के लिए आदर्श। UDP सॉकेट (socket.SOCK_DGRAM) तेज़ होते हैं पर अविश्वसनीय “फायर‑एंड‑फ़ॉरगेट” कनेक्शन देते हैं—वीडियो स्ट्रीमिंग, गेमिंग और IoT सेंसरों के लिए उपयुक्त।
मुझे नेटवर्क प्रोग्रामिंग के लिए Python सॉकेट्स या asyncio में क्या उपयोग करना चाहिए?
जब आपको सूक्ष्म‑स्तरीय नियंत्रण चाहिए या आप नेटवर्किंग कैसे काम करती है, यह सीख रहे हैं—तब raw सॉकेट उपयोग करें। अधिकांश प्रोडक्शन कोड के लिए asyncio उपयोग करें—यह थ्रेडिंग की तुलना में एक ही थ्रेड में हज़ारों कनेक्शन अधिक कुशलता से संभालता है। FastAPI और aiohttp दोनों asyncio पर आधारित हैं।
मैं Python सॉकेट्स के साथ कई क्लाइंट कैसे संभालूँ?
सबसे सरल तरीका मल्टीथ्रेडिंग है—हर कनेक्शन के लिए threading.Thread से नया थ्रेड स्पॉन करें। अधिक कॉनकरेंसी के लिए, एक ही थ्रेड में कई क्लाइंट संभालने हेतु asyncio का उपयोग करें। प्रोडक्शन में, स्टैंडर्ड लाइब्रेरी का socketserver मॉड्यूल तैयार ThreadingTCPServer और ForkingTCPServer क्लास देता है।
क्या Python सॉकेट कनेक्शन सुरक्षित होते हैं?
डिफ़ॉल्ट रूप से raw Python सॉकेट डेटा अनएन्क्रिप्टेड ट्रांसमिट करते हैं—ट्रैफ़िक को इंटरसेप्ट करने वाला कोई भी व्यक्ति उसे पढ़ सकता है। सुरक्षित संचार के लिए, बिल्ट‑इन ssl मॉड्यूल (ssl.SSLContext.wrap_socket()) का उपयोग करके अपने सॉकेट को TLS से रैप करें। किसी भी संवेदनशील डेटा के लिए प्रोडक्शन में हमेशा TLS का उपयोग करें।