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

सर्वर को एक क्वेरी वाला अनुरोध प्राप्त होता है और मनमाने ढंग से बड़े परिणाम स्ट्रीम करता है।

मैं कच्चे प्रदर्शन के बजाय सरल कोड पर जोर देने के साथ सी # 4 में उपलब्ध तकनीकों और पुस्तकालयों का उपयोग करके ऐसा करने का मूर्खतापूर्ण तरीका चाहता हूं।

फिर से खोलना एक सॉकेट सर्वर एक स्केलेबल सिस्टम का एक उपयोगी हिस्सा है। यदि आप क्षैतिज रूप से स्केल करना चाहते हैं, तो विभिन्न तकनीकें हैं। यदि आपने कभी सॉकेट सर्वर नहीं बनाया है तो आप शायद इस प्रश्न का उत्तर नहीं दे पाएंगे।

8
Dave Hillier 5 अक्टूबर 2011, 02:10

1 उत्तर

सबसे बढ़िया उत्तर

मैं एक या दो सप्ताह से कुछ इसी तरह पर काम कर रहा हूं, इसलिए उम्मीद है कि मैं आपकी थोड़ी मदद कर सकूंगा।

यदि आपका ध्यान सरल कोड पर है, तो मैं TcpClient और TcpListener कक्षाओं का उपयोग करने की सलाह दूंगा। वे दोनों सॉकेट को काम करने में बहुत आसान बनाते हैं। जबकि वे .NET Framework 1.1 के बाद से अस्तित्व में हैं, उन्हें अपडेट किया गया है और अभी भी आपकी सबसे अच्छी शर्त है।

सरल कोड लिखने में .NET Framework 4.0 का उपयोग करने के तरीके के संदर्भ में, कार्य पहली चीज है जो दिमाग में आती है। वे एसिंक्रोनस कोड लिखना बहुत कम दर्दनाक बनाते हैं और सी # 5 आने के बाद आपके कोड को माइग्रेट करना बहुत आसान हो जाएगा (नया async और प्रतीक्षित कीवर्ड)। यहां एक उदाहरण दिया गया है कि कैसे कार्य आपके कोड को सरल बना सकते हैं:

tcpListener.BeginAcceptTcpClient(AsyncCallback callback, object state); का उपयोग करने और एक कॉलबैक विधि प्रदान करने के बजाय जो EndAcceptTcpClient(); को कॉल करेगी और वैकल्पिक रूप से आपके राज्य ऑब्जेक्ट को कास्ट करेगी, C# 4 आपको इस प्रक्रिया को और अधिक पठनीय और स्केलेबल बनाने के लिए क्लोजर, लैम्ब्डा और टास्क का उपयोग करने की अनुमति देता है। यहाँ एक उदाहरण है:

private void AcceptClient(TcpListener tcpListener)
{
    Task<TcpClient> acceptTcpClientTask = Task.Factory.FromAsync<TcpClient>(tcpListener.BeginAcceptTcpClient, tcpListener.EndAcceptTcpClient, tcpListener);

    // This allows us to accept another connection without a loop.
    // Because we are within the ThreadPool, this does not cause a stack overflow.
    acceptTcpClientTask.ContinueWith(task => { OnAcceptConnection(task.Result); AcceptClient(tcpListener); }, TaskContinuationOptions.OnlyOnRanToCompletion);
}

private void OnAcceptConnection(TcpClient tcpClient)
{
    string authority = tcpClient.Client.RemoteEndPoint.ToString(); // Format is: IP:PORT

    // Start a new Task to handle client-server communication
}

FromAsync बहुत उपयोगी है जैसा कि माइक्रोसॉफ्ट के पास है कई अधिभार प्रदान किए जो सामान्य अतुल्यकालिक संचालन को सरल बना सकते हैं। यहाँ एक और उदाहरण है:

private void Read(State state)
{
    // The int return value is the amount of bytes read accessible through the Task's Result property.
    Task<int> readTask = Task<int>.Factory.FromAsync(state.NetworkStream.BeginRead, state.NetworkStream.EndRead, state.Data, state.BytesRead, state.Data.Length - state.BytesRead, state, TaskCreationOptions.AttachedToParent);

    readTask.ContinueWith(ReadPacket, TaskContinuationOptions.OnlyOnRanToCompletion);
    readTask.ContinueWith(ReadPacketError, TaskContinuationOptions.OnlyOnFaulted);
}

राज्य केवल एक उपयोगकर्ता-परिभाषित वर्ग है जिसमें आमतौर पर केवल TcpClient उदाहरण, डेटा (बाइट सरणी), और शायद बाइट्स भी पढ़े जाते हैं।

जैसा कि आप देख सकते हैं, जारी रखें का उपयोग बहुत सारे बोझिल try-catches को बदलने के लिए किया जा सकता है जो अब तक एक आवश्यक बुराई थी।

अपनी पोस्ट की शुरुआत में आपने उल्लेख किया था कि आप प्रति कनेक्शन एक थ्रेड नहीं बनाना चाहते हैं या बहुत लंबे समय तक चलने वाले कार्य नहीं करना चाहते हैं और मैंने सोचा कि मैं इस बिंदु पर इसे संबोधित करूंगा। व्यक्तिगत रूप से, मुझे प्रत्येक कनेक्शन के लिए थ्रेड बनाने में समस्या नहीं दिखाई देती है।

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

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

15
Ryan Peschel 5 अक्टूबर 2011, 02:57
धन्यवाद - यह वही है जो मैं ढूंढ रहा था!
 – 
Dave Hillier
5 अक्टूबर 2011, 02:50
5
प्रति कनेक्शन एक थ्रेड का उपयोग करते हुए लगभग 1 मिलियन कनेक्शन कैसे?
 – 
Shift
8 नवम्बर 2012, 10:56
एक मिलियन कनेक्शन के मामले में: linux का उपयोग करें। यदि आपको वास्तव में विंडोज़ का उपयोग करना है तो स्थिर चयन विधि का उपयोग करके एक थ्रेड में कई सॉकेट संभालें और उन्हें बुद्धिमान समूह बनाएं। इसके लिए टीसीपी क्लाइंट का उपयोग न करें, क्योंकि आप वास्तव में किसी भी ओवरहेड को बचा सकते हैं।
 – 
Matthias
20 अगस्त 2017, 06:26