टीसीपी: दो अलग-अलग सॉकेट एक पोर्ट साझा कर सकते हैं?


124

यह एक बहुत ही बुनियादी सवाल हो सकता है लेकिन यह मुझे भ्रमित करता है।

क्या दो अलग-अलग कनेक्ट किए गए सॉकेट एक पोर्ट साझा कर सकते हैं? मैं एक एप्लिकेशन सर्वर लिख रहा हूं जो 100k से अधिक समवर्ती कनेक्शनों को संभालने में सक्षम होना चाहिए, और हम जानते हैं कि एक सिस्टम पर उपलब्ध बंदरगाहों की संख्या लगभग 60k (16bit) है। एक जुड़ा सॉकेट एक नए (समर्पित) पोर्ट को सौंपा गया है, इसलिए इसका मतलब है कि समवर्ती कनेक्शन की संख्या बंदरगाहों की संख्या तक सीमित है, जब तक कि कई सॉकेट एक ही पोर्ट को साझा नहीं कर सकते। तो सवाल।

अग्रिम में मदद के लिए धन्यवाद!

जवाबों:


175

एक सर्वर सॉकेट एकल पोर्ट पर सुनता है। उस सर्वर पर सभी स्थापित क्लाइंट कनेक्शन कनेक्शन के सर्वर साइड पर उसी श्रवण पोर्ट से जुड़े होते हैं । क्लाइंट-साइड और सर्वर-साइड IP / पोर्ट जोड़े के संयोजन से एक स्थापित कनेक्शन विशिष्ट रूप से पहचाना जाता है। एक ही सर्वर पर कई कनेक्शन एक ही सर्वर-साइड आईपी ​​/ पोर्ट जोड़ी को साझा कर सकते हैं जब तक कि वे अलग - अलग क्लाइंट-साइड आईपी ​​/ पोर्ट जोड़े से जुड़े होते हैं , और सर्वर कई क्लाइंट को हैंडल करने में सक्षम होगा क्योंकि उपलब्ध सिस्टम संसाधन इसे अनुमति देते हैं सेवा।

पर क्लाइंट साइड , यह आम बात नई आउटबाउंड कनेक्शन एक यादृच्छिक का उपयोग करने के लिए है क्लाइंट साइड उपलब्ध बंदरगाहों से बाहर चलाने के लिए बंदरगाह, जिस स्थिति में यह संभव है यदि आप समय की एक छोटी राशि में बहुत-से संपर्क कर सकते हैं।


2
उत्तर के लिए धन्यवाद, रेमी! आपका उत्तर वह सब कुछ है जिसके बारे में मैं उत्सुक था। ;)
केजे

2
@ दुश्मन कनेक्शन न केवल स्रोत / गंतव्य पोर्ट / आईपी, बल्कि एक प्रोटोकॉल (टीसीपी, यूडीपी आदि) द्वारा भी भेदभाव किया जाता है, अगर मैं गलत नहीं हूं।
ओन्ड्रेज पीटरका

1
@OndraPeterka: हाँ, लेकिन सभी प्लेटफ़ॉर्म उस पर प्रतिबंधित नहीं हैं। उदाहरण के लिए, विंडोज खुशी-खुशी अलग IPv4 और IPv6 सर्वर सॉकेट को एक ही स्थानीय IP पर सुनने की अनुमति देता है: हुप्स के माध्यम से कूदने के बिना पोर्ट, लेकिन * निक्स सिस्टम (लिनक्स और एंड्रॉइड सहित) नहीं करते हैं।
रेमी लेबेऊ

6
@ user2268997: आप एकाधिक सर्वर से कनेक्ट करने के लिए एक सॉकेट का उपयोग नहीं कर सकते। आपको प्रत्येक कनेक्शन के लिए एक अलग सॉकेट बनाना होगा।
रेमी लेबेउ

3
@FernandoGonzalezSanchez: एक एकल क्लाइंट में कई टीसीपी सॉकेट हो सकते हैं, जो एक ही स्थानीय आईपी / पोर्ट जोड़ी के लिए बाध्य होते हैं, जब तक कि वे विभिन्न दूरस्थ आईपी / पोर्ट जोड़े से जुड़े होते हैं। यह विंडोज के लिए विशिष्ट नहीं है, यह टीसीपी सामान्य रूप से कैसे काम करता है, इसका एक हिस्सा है।
रेमी लेबेऊ

182

टीसीपी / एचटीटीपी पोर्ट पर सुन रहे हैं: कैसे कई उपयोगकर्ता एक ही पोर्ट साझा कर सकते हैं

तो, क्या होता है जब एक सर्वर टीसीपी पोर्ट पर आने वाले कनेक्शन के लिए सुनता है? उदाहरण के लिए, मान लें कि आपके पास पोर्ट 80 पर एक वेब-सर्वर है। मान लें कि आपके कंप्यूटर में 24.14.181.229 का सार्वजनिक आईपी पता है और जो व्यक्ति आपसे जुड़ने की कोशिश करता है, उसका आईपी पता 10.1.2.3 है। यह व्यक्ति 24.14.181.229:80 पर टीसीपी सॉकेट खोलकर आपसे जुड़ सकता है। काफी सरल।

सहज रूप से (और गलत तरीके से), ज्यादातर लोग मानते हैं कि यह कुछ इस तरह दिखता है:

    Local Computer    | Remote Computer
    --------------------------------
    <local_ip>:80     | <foreign_ip>:80

    ^^ not actually what happens, but this is the conceptual model a lot of people have in mind.

यह सहज है, क्योंकि क्लाइंट के दृष्टिकोण से, उसके पास एक आईपी पता है, और आईपी: पोर्ट पर एक सर्वर से जुड़ता है। चूँकि क्लाइंट 80 पोर्ट से जुड़ता है, तो उसका पोर्ट भी 80 होना चाहिए? यह सोचने वाली एक समझदारी है, लेकिन वास्तव में ऐसा नहीं है। यदि यह सही होना था, तो हम केवल एक उपयोगकर्ता प्रति विदेशी आईपी पते की सेवा कर सकते थे। एक बार एक दूरस्थ कंप्यूटर कनेक्ट हो जाता है, तो वह पोर्ट 80 को पोर्ट 80 कनेक्शन के लिए बंद कर देगा, और कोई भी कनेक्ट नहीं कर सकता है।

तीन बातों को समझना चाहिए:

1.) एक सर्वर पर, एक प्रक्रिया एक बंदरगाह पर सुन रही है। एक बार जब यह एक कनेक्शन हो जाता है, यह इसे एक और धागे को सौंप देता है। संचार सुनने के बंदरगाह को कभी नहीं हिलाता है।

2.) निम्नलिखित 5-ट्यूपल द्वारा ओएस द्वारा कनेक्शन को विशिष्ट रूप से पहचाना जाता है: (स्थानीय-आईपी, स्थानीय-पोर्ट, रिमोट-आईपी, रिमोट-पोर्ट, प्रोटोकॉल)। यदि टपल में कोई तत्व अलग है, तो यह पूरी तरह से स्वतंत्र कनेक्शन है।

3.) जब कोई क्लाइंट किसी सर्वर से जुड़ता है, तो यह एक यादृच्छिक, अप्रयुक्त उच्च-क्रम स्रोत पोर्ट चुनता है । इस तरह, एक ही क्लाइंट के पास एक ही डेस्टिनेशन पोर्ट के लिए सर्वर में ~ 64 k कनेक्शन हो सकते हैं।

जब ग्राहक किसी सर्वर से जुड़ता है, तो यह वास्तव में क्या होता है:

    Local Computer   | Remote Computer           | Role
    -----------------------------------------------------------
    0.0.0.0:80       | <none>                    | LISTENING
    127.0.0.1:80     | 10.1.2.3:<random_port>    | ESTABLISHED

असल में होता क्या है

सबसे पहले, चलो कंप्यूटर पर क्या हो रहा है यह देखने के लिए netstat का उपयोग करें। हम 80 के बजाय पोर्ट 500 का उपयोग करेंगे (क्योंकि सामान का एक पूरा गुच्छा पोर्ट 80 पर हो रहा है क्योंकि यह एक सामान्य पोर्ट है, लेकिन कार्यात्मक रूप से इससे कोई फर्क नहीं पड़ता है)।

    netstat -atnp | grep -i ":500 "

जैसा कि अपेक्षित था, आउटपुट रिक्त है। अब एक वेब सर्वर शुरू करते हैं:

    sudo python3 -m http.server 500

अब, यहां फिर से नेटस्टैट चलाने का आउटपुट है:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      - 

तो अब एक प्रक्रिया है जो सक्रिय रूप से सुन रही है (राज्य: लिस्टेन) पोर्ट 500 पर। स्थानीय पता 0.0.0.0 है, जो "सभी आईपी पते के लिए सुनने" के लिए कोड है। एक आसान गलती केवल पोर्ट 127.0.0.1 पर सुनना है, जो केवल वर्तमान कंप्यूटर से कनेक्शन स्वीकार करेगा। तो यह एक कनेक्शन नहीं है, इसका मतलब यह है कि आईपी को पोर्ट करने के लिए बाइंड () करने के लिए अनुरोध की गई प्रक्रिया, और यह प्रक्रिया उस पोर्ट के सभी कनेक्शनों को संभालने के लिए जिम्मेदार है। यह सीमा तक संकेत देता है कि पोर्ट पर सुनने वाले कंप्यूटर पर केवल एक ही प्रक्रिया हो सकती है (मल्टीप्लेक्सिंग का उपयोग करते हुए चारों ओर पाने के तरीके हैं, लेकिन यह बहुत अधिक जटिल विषय है)। यदि कोई वेब-सर्वर पोर्ट 80 पर सुन रहा है, तो वह उस पोर्ट को अन्य वेब-सर्वर के साथ साझा नहीं कर सकता है।

तो अब, एक उपयोगकर्ता को हमारी मशीन से कनेक्ट करते हैं:

    quicknet -m tcp -t localhost:500 -p Test payload.

यह एक साधारण स्क्रिप्ट ( https://github.com/grokit/quickweb ) है जो एक टीसीपी सॉकेट खोलता है, पेलोड भेजता है (इस मामले में "टेस्ट पेलोड"), कुछ सेकंड इंतजार करता है और डिस्कनेक्ट करता है। नेटस्टैट को फिर से करते हुए यह हो रहा है निम्नलिखित प्रदर्शित करता है:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      -
    tcp        0      0 192.168.1.10:500        192.168.1.13:54240      ESTABLISHED -

यदि आप किसी अन्य ग्राहक के साथ जुड़ते हैं और फिर से नेटस्टैट करते हैं, तो आप निम्नलिखित देखेंगे:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      -
    tcp        0      0 192.168.1.10:500        192.168.1.13:26813      ESTABLISHED -

... अर्थात्, क्लाइंट ने कनेक्शन के लिए एक और यादृच्छिक पोर्ट का उपयोग किया। इसलिए आईपी पतों के बीच कभी भ्रम नहीं होता है।


11
यह सबसे अच्छा जवाब है जो मैंने एसओ पर कभी देखा है।
नौकरियां

1
@ N0thing "इस तरह, एक एकल क्लाइंट के पास एक ही गंतव्य पोर्ट के लिए सर्वर के लिए ~ 64 k कनेक्शन हो सकते हैं।" तो व्यवहार में, यदि कोई ग्राहक एक ही सर्वर और पोर्ट से, दो बार या कई बार समवर्ती रूप से कनेक्ट नहीं होता है, तो एक ग्राहक के पास ~ 64K कनेक्शन से भी अधिक हो सकता है। क्या यह सच है। यदि हाँ तो इसका तात्पर्य यह है कि क्लाइंट की ओर से एक ही पोर्ट से इसका कई अलग-अलग सर्वर प्रक्रियाओं से कनेक्शन हो सकता है (जैसे कि सॉकेट कनेक्शन अलग है)। तो सभी में, कई क्लाइंट सॉकेट क्लाइंट मशीन पर एक ही पोर्ट पर निवास कर सकते हैं? कृपया "रेमी लेबेऊ" उत्तर के लिए मेरी टिप्पणी पढ़ें।
साभार

6
@premktiw: हां, कई क्लाइंट सॉकेट एक ही समय में एक ही स्थानीय आईपी / पोर्ट जोड़ी के लिए बाध्य हो सकते हैं, यदि वे अलग-अलग सर्वर आईपी / पोर्ट जोड़े से जुड़े होते हैं तो स्थानीय + दूरस्थ जोड़े के ट्यूपल्स अद्वितीय होते हैं। और हाँ, क्लाइंट के लिए कुल 64K से अधिक समवर्ती कनेक्शन होना संभव है। जब तक सर्वर IP / पोर्ट जोड़े अद्वितीय होते हैं, तब तक एकल पोर्ट से, इसे संभावित रूप से अनंत संख्या में सर्वर (उपलब्ध OS संसाधनों, उपलब्ध राउटर पोर्ट आदि) से जोड़ा जा सकता है।
रेमी लेबेउ

1
@RemyLebeau संतुष्ट। थैंक यू
वेरी मच

1
@bibst जब सभी आने वाले कनेक्शन अस्वीकार कर रहे हैं, तो फ़ायरवॉल यादृच्छिक बंदरगाहों से कैसे निपटता है?
पेट्रीकग

35

एक जुड़ा सॉकेट एक नए (समर्पित) पोर्ट को सौंपा गया है

यह एक सामान्य अंतर्ज्ञान है, लेकिन यह गलत है। एक कनेक्टेड सॉकेट को एक नए / समर्पित पोर्ट को नहीं सौंपा गया है। टीसीपी स्टैक को संतुष्ट करने वाला एकमात्र वास्तविक अवरोध यह है कि प्रत्येक सॉकेट कनेक्शन के लिए (लोकल_ड्रेस, लोकल_पोर्ट, रिमोट_एड्रेस, रिमोट_पोर्ट) का टपल अद्वितीय होना चाहिए। इस प्रकार सर्वर में एक ही स्थानीय पोर्ट का उपयोग करते हुए कई टीसीपी सॉकेट हो सकते हैं, जब तक कि पोर्ट पर प्रत्येक सॉकेट एक अलग दूरस्थ स्थान से जुड़ा हो।

"सॉकेट जोड़ी" पैराग्राफ को देखें: http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA52&dq=socket%20pair%20tuple&pg=PA52#v.onepage&q=socket%20pair%20tuple&f=false


1
सही जवाब के लिए धन्यवाद, जेरेमी!
केजे

6
आप जो कहते हैं वह सर्वर साइड के बारे में पूरी तरह सच है। हालांकि बीएसडी सॉकेट्स एपीआई की संरचना का अर्थ है कि आउटगोइंग क्लाइंट-साइड पोर्ट व्यवहार में अद्वितीय होना चाहिए, क्योंकि bind()ऑपरेशन ऑपरेशन से पहले connect(), यहां तक ​​कि अंतर्निहित भी है।
लोर्ने

1
@ ईजेपी हाय, मैंने सोचा कि bind()सर्वर साइड में केवल उपयोग किया जाता है इससे पहले कि accept()?ग्राहक पक्ष विशेष पोर्ट को भी बांध देगा?
GMsoF

5
@GMsoF: bind()का इस्तेमाल क्लाइंट की तरफ से पहले किया जा सकता है connect()
रेमी लेबेऊ

10

सैद्धांतिक रूप से, हाँ। अभ्यास, नहीं। अधिकांश कर्नेल (incl। Linux) आपको bind()पहले से आवंटित पोर्ट में एक सेकंड की अनुमति नहीं देता है । यह अनुमति देने के लिए वास्तव में बड़ा पैच नहीं थे।

वैचारिक रूप से, हमें सॉकेट और पोर्ट के बीच अंतर करना चाहिए । सॉकेट्स द्विदिश संचार अंत बिंदु हैं, अर्थात "चीजें" जहां हम बाइट भेज और प्राप्त कर सकते हैं। यह एक वैचारिक बात है, "सॉकेट" नाम के पैकेट हेडर में ऐसा कोई क्षेत्र नहीं है।

पोर्ट एक पहचानकर्ता है जो सॉकेट की पहचान करने में सक्षम है। टीसीपी के मामले में, एक पोर्ट 16 बिट पूर्णांक है, लेकिन अन्य प्रोटोकॉल भी हैं (उदाहरण के लिए, यूनिक्स सॉकेट्स पर, "पोर्ट" अनिवार्य रूप से एक स्ट्रिंग है)।

मुख्य समस्या निम्नलिखित है: यदि कोई आवक पैकेट आता है, तो कर्नेल अपने गर्तिका को उसके गंतव्य पोर्ट नंबर से पहचान सकता है। यह सबसे आम तरीका है, लेकिन यह एकमात्र संभावना नहीं है:

  • आने वाले पैकेट के गंतव्य आईपी द्वारा सॉकेट्स की पहचान की जा सकती है। यह मामला है, उदाहरण के लिए, अगर हमारे पास एक सर्वर दो IPs का एक साथ उपयोग होता है। फिर हम चल सकते हैं, उदाहरण के लिए, एक ही बंदरगाहों पर विभिन्न वेबसर्वर, लेकिन अलग-अलग आईपी पर।
  • सॉकेट को उनके स्रोत पोर्ट और आईपी द्वारा भी पहचाना जा सकता है । कई लोड संतुलन कॉन्फ़िगरेशन में यह मामला है।

क्योंकि आप एक एप्लिकेशन सर्वर पर काम कर रहे हैं, यह ऐसा करने में सक्षम होगा।


2
उन्होंने दूसरा बनाने के बारे में नहीं पूछा bind()
लोर्ने

1
@ user207421 क्या आपने कभी ऐसा ओएस देखा है जहां सुनकर सॉकेट्स स्थापित नहीं होते हैं bind()? मैं इसकी कल्पना कर सकता हूं, हां यह काफी संभव है, लेकिन तथ्य यह है कि WinSock और Posix API दोनों इसके लिए bind()कॉल का उपयोग करते हैं , यहां तक ​​कि उनका पैरामीरिजेशन भी व्यावहारिक रूप से समान है। यहां तक ​​कि अगर एक एपीआई में यह कॉल नहीं है, तो किसी तरह आपको यह कहने की ज़रूरत है कि आप आने वाले बाइट्स को कहां से पढ़ना चाहते हैं
पेटेर - मोनिका

1
@ user207421 100k या उससे अधिक टीसीपी कनेक्शन को एक ही पोर्ट के साथ संभाला जा सकता है, listen()/ accept()एपीआई कॉल एक तरह से सॉकेट बना सकते हैं जिससे कर्नेल उनके आने वाले पोर्ट्स से अलग हो जाएगा। ओपी के सवाल की व्याख्या इस तरह से की जा सकती है कि वह इसके लिए अनिवार्य रूप से पूछता है। मुझे लगता है, यह काफी यथार्थवादी है, लेकिन यह नहीं है कि उसके सवाल का शाब्दिक अर्थ क्या है।
पीटर - मोनिका

1

नहीं। किसी विशेष इंस्टेंट पर एक ही पोर्ट को साझा करना संभव नहीं है। लेकिन आप अपने एप्लिकेशन को इस तरह से बना सकते हैं कि यह पोर्ट को अलग-अलग समय पर एक्सेस कर देगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.