क्या बेहतर है? बहुत छोटे टीसीपी पैकेट, या एक लंबे एक? [बन्द है]


16

मैं एक सर्वर के लिए और एक गेम के लिए काफी डेटा भेज रहा हूं, जो मैं बना रहा हूं।

मैं वर्तमान में इस तरह स्थान डेटा भेजता हूं:

sendToClient((("UID:" + cl.uid +";x:" + cl.x)));
sendToClient((("UID:" + cl.uid +";y:" + cl.y)));
sendToClient((("UID:" + cl.uid +";z:" + cl.z)));

जाहिर है कि यह संबंधित एक्स, वाई और जेड मान भेज रहा है।

क्या इस तरह से डेटा भेजना अधिक कुशल होगा?

sendToClient((("UID:" + cl.uid +"|" + cl.x + "|" + cl.y + "|" + cl.z)));

2
मेरे सीमित अनुभव में पैकेट का नुकसान आमतौर पर 5% से कम है।
मुशाहो

5
क्या SendToClient वास्तव में एक पैकेट भेजता है? यदि हां, तो आपने इसे कैसे किया?
user253751

1
@mucaho मैंने इसे कभी भी खुद या कुछ भी नहीं मापा है, लेकिन मुझे आश्चर्य है कि टीसीपी किनारों के आसपास है। मैं 0.5% या उससे कम की तरह कुछ के लिए उम्मीद है।
पैन्ज़रक्रिसिस

1
@Panzercrisis मुझे आपसे सहमत होना चाहिए। मुझे व्यक्तिगत रूप से लगता है कि 5% की हानि अस्वीकार्य होगी। यदि आप मुझे भेजने जैसे कुछ के बारे में सोचते हैं, तो कहते हैं, एक नया जहाज खेल में पैदा हुआ, यहां तक ​​कि उस पैकेट के प्राप्त होने का 1% मौका भी विनाशकारी नहीं होगा, क्योंकि मुझे अदृश्य जहाज मिलेंगे।
joehot200

2
दोस्तों, मैं 5% एक ऊपरी बंधे के रूप में नहीं है। वास्तव में यह अन्य टिप्पणियों के अनुसार बहुत बेहतर है।
मुशाहो

जवाबों:


28

एक टीसीपी सेगमेंट में बहुत अधिक ओवरहेड है। जब आप एक टीसीपी पैकेट के साथ 10 बाइट संदेश भेजते हैं, तो आप वास्तव में भेजते हैं:

  • IPv4 हेडर के 16 बाइट्स (IPv6 के सामान्य होने पर 40 बाइट तक बढ़ जाएंगे)
  • टीसीपी हेडर के 16 बाइट्स
  • पेलोड के 10 बाइट्स
  • उपयोग किए गए डेटा-लिंक और भौतिक परत प्रोटोकॉल के लिए अतिरिक्त ओवरहेड

10 बाइट डेटा के परिवहन के लिए 42 बाइट्स के परिणामस्वरूप। इसलिए आप केवल अपने उपलब्ध बैंडविड्थ के 25% से कम का उपयोग करते हैं। और यह अभी भी ओवरहेड के लिए खाता नहीं है जो कि निचले स्तर के प्रोटोकॉल जैसे ईथरनेट या पीपीपीओई खपत करते हैं (लेकिन ये अनुमान लगाना कठिन है क्योंकि बहुत सारे विकल्प हैं)।

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

इस कारण से आपको एक टीसीपी सेगमेंट में एक बार में उपलब्ध सभी डेटा भेजने की कोशिश करनी चाहिए।

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

जब यह एक समस्या है, तो आप हमेशा यूडीपी का उपयोग कर सकते हैं। लेकिन फिर आपको खोए हुए और आउट-ऑफ-ऑर्डर संदेशों के लिए अपना समाधान खोजने की आवश्यकता है (यह कम से कम यह गारंटी देता है कि संदेश जो करते हैं आने, पूर्ण और undamaged पहुंचें)।


1
क्या टीसीपी पैकेट के आकार के आधार पर जिस तरह से टीसीपी पैकेट नुकसान को अलग करता है, उससे ओवरहेड होता है?
पैंजरक्रिसिस

@Panzercrisis केवल में अब तक एक बड़ा पैकेट है जिसे नाराज होने की आवश्यकता है।
फिलिप

8
मैं यह नोट करूँगा कि OS लगभग निश्चित रूप से Nagles Algorithm en.wikipedia.org/wiki/Nagle%27s_algorithm को आउटगोइंग डेटा पर लागू करेगा , इसका मतलब यह है कि यदि आप अलग-अलग लिखते हैं या संयोजन करते हैं तो इससे कोई फर्क नहीं पड़ता, यह उन्हें संयोजित करेगा वास्तव में टीसीपी के माध्यम से उन्हें पास करने से पहले।
वलिटी

1
@Vality अधिकांश सॉकेट एपीआई जिनका मैंने उपयोग किया है, प्रत्येक सॉकेट के लिए नागल को सक्रिय या निष्क्रिय करने की अनुमति देता है। अधिकांश खेलों के लिए मैं इसे निष्क्रिय करने की सलाह दूंगा, क्योंकि कम विलंबता आमतौर पर बैंडविड्थ के संरक्षण से अधिक महत्वपूर्ण है।
फिलिप

4
नागल का एल्गोरिदम एक है, लेकिन एकमात्र कारण डेटा भेजने वाले पक्ष पर बफर नहीं किया जा सकता है। डेटा भेजने को मज़बूती से लागू करने का कोई तरीका नहीं है। इसके अलावा, बफ़रिंग / विखंडन डेटा भेजे जाने के बाद कहीं भी हो सकता है, या तो NATs, राउटर, परदे के पीछे, या यहां तक ​​कि प्राप्त करने वाला पक्ष। टीसीपी उस आकार और समय के बारे में कोई गारंटी नहीं देता है जिस पर आप डेटा प्राप्त करते हैं, केवल यह कि यह क्रम में और मज़बूती से आएगा। यदि आपको आकार की गारंटी की आवश्यकता है, तो यूडीपी का उपयोग करें। तथ्य यह है कि टीसीपी को समझना आसान लगता है, यह सभी समस्याओं के लिए सबसे अच्छा उपकरण नहीं है!
पांडा पायजामा

10

एक बड़ा एक (कारण के भीतर) बेहतर है।

जैसा कि आपने कहा, पैकेट की हानि इसका मुख्य कारण है। पैकेट आमतौर पर एक निश्चित आकार के फ़्रेम में भेजे जाते हैं, इसलिए 10 फ़्रेम वाले 10 फ़्रेम वाले बड़े संदेश के साथ एक फ्रेम लेना बेहतर होता है।

हालाँकि, मानक TCP के साथ, यह वास्तव में कोई समस्या नहीं है, जब तक कि आप इसे अक्षम न करें। (इसे नागल के एल्गोरिथ्म कहा जाता है , और खेलों के लिए आपको इसे अक्षम करना चाहिए।) टीसीपी एक निश्चित समय समाप्त होने तक या जब तक पैकेज "पूर्ण" नहीं होगा। जहां "फुल" कुछ थोड़ा मैजिक नंबर होगा, जिसे फ्रेम साइज के हिसाब से तय किया जाएगा।


मैंने नागले के एल्गोरिथ्म के बारे में सुना है, लेकिन क्या इसे निष्क्रिय करना वास्तव में एक अच्छा विचार है? मैं सिर्फ एक StackOverflow जवाब से आया, जहां किसी ने कहा कि यह अधिक कुशल है (और स्पष्ट कारणों से मुझे दक्षता चाहिए)।
joehot200

6
@ joehot200 इसका एकमात्र सही उत्तर "यह निर्भर करता है" है। यह बहुत सारे डेटा भेजने के लिए अधिक कुशल है, हाँ, लेकिन वास्तविक समय की स्ट्रीमिंग के लिए नहीं जो गेम की आवश्यकता है।
डी-साइड

4
@ joehot200: नागल का एल्गोरिथ्म एक विलंबित-पावती एल्गोरिथ्म के साथ खराब बातचीत करता है जो कुछ टीसीपी कार्यान्वयन कभी-कभी उपयोग करते हैं। कुछ डेटा मिलने के बाद यदि वे अधिक डेटा की उम्मीद करते हैं, तो कुछ टीसीपी कार्यान्वयन एसीके भेजने में देरी करेंगे क्योंकि (बाद के पैकेट को स्वीकार करने के बाद पहले वाले को भी स्वीकार कर लेंगे)। नागल के एल्गोरिथ्म का कहना है कि एक इकाई को आंशिक पैकेट नहीं भेजना चाहिए अगर उसने कुछ डेटा भेजा है लेकिन एक पावती नहीं सुनी है। कभी-कभी दोनों दृष्टिकोण बुरी तरह से बातचीत करते हैं, प्रत्येक पक्ष कुछ करने के लिए दूसरे की प्रतीक्षा कर रहा है, ...
Supercat

2
... एक "पवित्रता टाइमर" में किक करता है और स्थिति को हल करता है (एक सेकंड के आदेश पर)।
सुपरकैट

2
दुर्भाग्य से, नागल के एल्गोरिथ्म को अक्षम करने से अन्य मेजबान पक्ष पर बफरिंग को रोकने के लिए कुछ भी नहीं होगा। नागल के एल्गोरिथ्म को अक्षम करने से यह सुनिश्चित नहीं होता है कि आपको recv()प्रत्येक send()कॉल के लिए एक कॉल मिलता है , जो कि ज्यादातर लोग ढूंढ रहे हैं। एक प्रोटोकॉल का उपयोग करना जो इसकी गारंटी देता है, जैसे कि यूडीपी करता है। "जब आपके पास टीसीपी है, तो सब कुछ एक धारा की तरह दिखता है"
पांडा पायजामा

6

पिछले सभी उत्तर गलत हैं। व्यवहार में, इससे कोई फर्क नहीं पड़ता कि आप एक लंबी send()कॉल जारी करते हैं या कई छोटेsend() कॉल जारी करते हैं।

फिलिप राज्यों के अनुसार, एक टीसीपी सेगमेंट में कुछ ओवरहेड होता है, लेकिन एप्लिकेशन प्रोग्रामर के रूप में, आपके पास इस बात पर कोई नियंत्रण नहीं होता है कि सेगमेंट कैसे उत्पन्न होते हैं। आसान शब्दों में:

एक send()कॉल आवश्यक रूप से एक टीसीपी खंड में अनुवाद नहीं करता है।

ओएस पूरी तरह से मुफ्त है आपके सभी डेटा को बफर करने और एक सेगमेंट में भेजने के लिए है, या लंबे समय तक ले जाए और इसे कई छोटे सेगमेंट में तोड़ दे।

इसके कई निहितार्थ हैं, लेकिन सबसे महत्वपूर्ण यह है कि:

एक send()कॉल, या एक टीसीपी सेगमेंट जरूरी नहीं कि recv()दूसरे छोर पर एक सफल कॉल का अनुवाद हो

इसके पीछे तर्क यह है कि टीसीपी एक स्ट्रीम प्रोटोकॉल है। टीसीपी आपके डेटा को बाइट्स की एक लंबी धारा के रूप में मानता है, और इसमें "पैकेट" की कोई अवधारणा नहीं है। आपके साथ send()उस स्ट्रीम में बाइट्स जोड़ते हैं, और recv()दूसरी तरफ से बाइट्स प्राप्त करते हैं। टीसीपी आक्रामक रूप से आपके डेटा को अलग-अलग बफर और विभाजित करेगा जहां भी यह सुनिश्चित करने के लिए फिट बैठता है कि आपका डेटा दूसरी तरफ जितनी जल्दी हो सके।

यदि आप टीसीपी के साथ "पैकेट" भेजना और प्राप्त करना चाहते हैं, तो आपको पैकेट स्टार्ट मार्कर, लंबाई मार्कर और इतने पर लागू करना होगा। UDP जैसे संदेश उन्मुख प्रोटोकॉल का उपयोग करने के बारे में कैसे? यूडीपी send()एक भेजे गए डेटाग्राम और एक recv()कॉल पर एक अनुवाद की गारंटी देता है !

जब आपके पास टीसीपी है, तो सब कुछ एक स्ट्रीम की तरह दिखता है


1
प्रत्येक संदेश को संदेश की लंबाई के साथ जोड़ना इतना मुश्किल नहीं है।
ysdx

पैकेट एग्रीगेशन की बात आते ही आपके पास फ्लिप करने के लिए एक स्विच होता है, चाहे नागले का एल्गोरिदम प्रभावी हो या न हो। यह असामान्य नहीं है कि यह अंडरफ़िल्ड पैकेट की शीघ्र डिलीवरी सुनिश्चित करने के लिए गेम नेटवर्किंग में बंद है।
लार्स विकलंड

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

@ysdx: नहीं, भेजने वाले पक्ष पर नहीं, लेकिन प्राप्त पक्ष पर हाँ। चूंकि आपके पास कोई गारंटी नहीं है कि वास्तव में आपको कहां पर डेटा मिलेगा recv(), आपको इसकी भरपाई करने के लिए अपनी स्वयं की बफरिंग बनाने की आवश्यकता है। मैं इसे यूडीपी पर विश्वसनीयता लागू करने में उसी कठिनाई में रैंक करूंगा।
पांडा पायजामा

@ पगंडा पायजामा: प्राप्त पक्ष का एक भोली कार्यान्वयन है: while(1) { uint16_t size; read(sock, &size, sizeof(size)); size = ntoh(size); char message[size]; read(sock, buffer, size); handleMessage(message); }(चूक की हैंडलिंग और संक्षिप्तता के लिए आंशिक रीडिंग लेकिन यह बहुत अधिक नहीं बदलता है)। ऐसा करना selectअधिक जटिलता नहीं जोड़ता है और यदि आप टीसीपी का उपयोग कर रहे हैं तो आपको आंशिक संदेशों को वैसे भी बफर करने की आवश्यकता होगी। यूडीपी पर मजबूत विश्वसनीयता को लागू करना उससे कहीं अधिक जटिल है।
ysdx

3

कई छोटे पैकेज ठीक हैं। वास्तव में, यदि आप टीसीपी ओवरहेड के बारे में चिंतित हैं, तो बस एक डालेंbufferstream 1500 चार्ट्स (या जो भी आपके टीसीपी एमटीयू है, उसे गतिशील रूप से अनुरोध करने के लिए सबसे अच्छा है) , और एक स्थान पर समस्या से निपटें। ऐसा करने से आपको हर अतिरिक्त पैकेज के लिए ~ 40 बाइट्स का ओवरहेड मिल जाता है जो आपने अन्यथा बनाया होता।

उस ने कहा, यह अभी भी कम डेटा भेजने के लिए बेहतर है, और बड़ी वस्तुओं के निर्माण में मदद करता है। बेशक यह भेजने की "UID:10|1|2|3तुलना में छोटा है UID:10;x:1UID:10;y:2UID:10;z:3। वास्तव में, इस बिंदु पर भी आपको पहिया को सुदृढ़ नहीं किया जाना चाहिए, प्रोटोबुफ़ जैसी लाइब्रेरी का उपयोग करें जो डेटा को 10 बाइट स्ट्रिंग या उससे कम कर सकता है।

केवल एक चीज जिसे आपको नहीं भूलना चाहिए, वह है Flushप्रासंगिक स्थानों पर अपनी स्ट्रीम पर एक कमांड डालना, क्योंकि जैसे ही आप अपनी स्ट्रीम में डेटा जोड़ना बंद करते हैं, यह कुछ भी भेजने से पहले अनंत प्रतीक्षा कर सकता है। वास्तव में समस्याग्रस्त है जब आपका ग्राहक उस डेटा की प्रतीक्षा कर रहा है, और जब तक कि ग्राहक अगली कमांड नहीं भेजते तब तक आपका गंभीर कुछ भी नया नहीं भेजेगा।

पैकेज की हानि ऐसी चीज है जिसे आप यहां, मामूली रूप से प्रभावित कर सकते हैं। आपके द्वारा भेजा गया प्रत्येक बाइट संभावित रूप से दूषित हो सकता है, और टीसीपी स्वचालित रूप से एक पुनः प्राप्ति का अनुरोध करेगा। छोटे पैकेज का मतलब है कि हर एक पैकेज के भ्रष्ट होने की संभावना कम है, लेकिन क्योंकि वे ओवरहेड पर जोड़ते हैं, आप और भी अधिक बाइट भेजते हैं, एक खोए हुए पैकेज की बाधाओं को और अधिक बढ़ाते हैं। जब एक पैकेज खो जाता है, तो टीसीपी सभी सफल डेटा को तब तक बफर करेगा जब तक कि लापता पैकेज को फिर से शुरू और प्राप्त नहीं किया जाता है। यह एक बड़ी देरी (पिंग) में परिणाम है। जबकि पैकेज की हानि के कारण बैंडविड्थ में कुल नुकसान नगण्य हो सकता है, उच्च पिंग खेल के लिए अवांछनीय होगा।

निचला रेखा: जितना संभव हो उतना कम डेटा भेजें, बड़े पैकेज भेजें, और ऐसा करने के लिए अपने स्वयं के निम्न स्तर के तरीके न लिखें, लेकिन bufferstreamभारी उठाने को संभालने के लिए अच्छी तरह से ज्ञात पुस्तकालयों और जैसे और प्रोटोबुफ़ पर भरोसा करें ।


वास्तव में इस तरह की सरल चीजों के लिए अपने स्वयं के रोल करना आसान है। किसी अन्य व्यक्ति के पुस्तकालय का उपयोग करने के लिए 50 पृष्ठ के दस्तावेज़ के माध्यम से जाने की तुलना में बहुत आसान है, और उसके बाद आपको अभी भी उनके बग और गोच से निपटने के लिए मिला है।
पेसियर

सच है, अपना खुद bufferstreamका लिखना तुच्छ है, इसलिए मैंने इसे एक विधि कहा है। आप अभी भी इसे एक स्थान पर संभालना चाहते हैं, और अपने संदेश कोड के साथ अपने बफर तर्क को एकीकृत नहीं करते हैं। ऑब्जेक्ट सीरियलाइजेशन के लिए, मुझे अत्यधिक संदेह है कि आप हजारों-घंटे दूसरों की तुलना में कुछ बेहतर करते हैं, भले ही आप कोशिश करते हों, मैं दृढ़ता से आपको ज्ञात कार्यान्वयन के खिलाफ अपने समाधान का सुझाव देता हूं।
डोरस

2

हालाँकि खुद को प्रोग्रामिंग करने के लिए एक नवजात शिशु होने के नाते, मैं कुछ बिंदुओं को जोड़कर अपने सीमित अनुभव को साझा करना चाहता हूं:

  • टीसीपी एक ओवरहेड करता है - आपको संबंधित आँकड़ों को मापना चाहिए
  • UDP नेटवर्क गेमिंग परिदृश्यों के लिए वास्तविक समाधान है, लेकिन सभी कार्यान्वयन जो इस पर भरोसा करते हैं, पैकेट खो जाने या ऑर्डर से बाहर भेजे जाने के लिए एक अतिरिक्त, सीपीयू-साइड एल्गोरिथ्म है।

मापन के बारे में, जिन मीट्रिक पर विचार किया जाना चाहिए वे हैं:

  • मतलब और तत्काल थ्रूपुट
  • औसत , अधिकतम और न्यूनतम अंत-टू-एंड देरी ऐसे मैट्रिक्स के लिए, मौजूदा उपकरण एक तेज समाधान प्रदान कर सकते हैं। उदाहरण के लिए: iperf ( https://iperf.fr/ ), D-ITG ( http://traffic.comics.unina.it/software/ITG/ )। ट्यूनिंग टीसीपी पर एक दिनांकित लेकिन अभी भी उपयोगी दस्तावेज पाया जा सकता है http://dst.lbl.gov/publications/usenix-login.pdf

जैसा कि उल्लेख किया गया है, अगर आपको पता चलता है कि आप एक अर्थ में सीमित नहीं हैं और यूडीपी का उपयोग कर सकते हैं, तो उसके लिए जाएं। वहाँ कुछ यूडीपी-आधारित कार्यान्वयन हैं, इसलिए आपको वर्षों के अनुभव और सिद्ध अनुभव के खिलाफ पहिया या काम को फिर से करने की आवश्यकता नहीं है। उल्लेख के लायक ऐसे कार्यान्वयन हैं:

  • विश्वसनीय यूडीपी http://sourceforge.net/projects/rudp/
  • ENET http://enet.bespin.org/ (जो बेहतर प्रदर्शन करने पर पाया गया कि टीसीपी संदेश हैंडलिंग को भी बदल सकता है)
  • UDT (UDP- आधारित डेटा ट्रांसफर प्रोटोकॉल http://udt.sourceforge.net/ ) जो HP कंप्यूटिंग परिदृश्यों में आदर्श बन गया है

निष्कर्ष: चूंकि एक यूडीपी कार्यान्वयन टीसीपी एक के मुकाबले (3x के एक कारक द्वारा) बेहतर प्रदर्शन कर सकता है, एक बार आपने यूडीपी के अनुकूल होने के लिए अपने परिदृश्य की पहचान कर ली है, तो यह विचार करने के लिए समझ में आता है। चेतावनी दी! यूडीपी के शीर्ष पर पूर्ण टीसीपी स्टैक को लागू करना हमेशा एक बुरा विचार है।


मैं यूडीपी का उपयोग कर रहा था। मैंने केवल टीसीपी पर स्विच किया है। UDP के पैकेट का नुकसान ग्राहक को आवश्यक डेटा के लिए अस्वीकार्य था। मैं यूडीपी के माध्यम से आंदोलन डेटा भेज सकता हूं।
joehot200

तो, सबसे अच्छी चीजें जो आप कर सकते हैं: वास्तव में, टीसीपी केवल महत्वपूर्ण संचालन के लिए उपयोग करें या यूडीपी आधारित सॉफ़्टवेयर प्रोटोकॉल कार्यान्वयन का उपयोग करें (एनट सरल होने के साथ और यूडीटी अच्छी तरह से परीक्षण किया जा रहा है)। लेकिन पहले, नुकसान को मापें और तय करें कि क्या यूडीटी आपको बढ़त दिलाएगा।
तेयोद्रोन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.