2011-01-25 14 views
6

मेरे पास एक पुरानी प्रोजेक्ट है: डीसीओएम क्लाइंट और सर्वर, दोनों सी ++ \ एटीएल, केवल विंडोज प्लेटफार्म में। सबकुछ ठीक काम करता है: स्थानीय और रिमोट क्लाइंट सर्वर से कनेक्ट होते हैं और किसी भी समस्या के बिना एक साथ काम करते हैं।DCOM: क्लाइंट क्रैश पर सर्वर में कनेक्शन कैसे बंद करें?

लेकिन जब दूरस्थ क्लाइंट टास्क मैनेजर द्वारा या "टास्ककिल" कमांड या पावर स्विच द्वारा मारा जाता है - मुझे कोई समस्या है। मेरा सर्वर क्लाइंट क्रैश के बारे में कुछ भी नहीं जानता है और सभी ग्राहकों को नई घटनाएं भेजने की कोशिश करता है (पहले से ही क्रैश होने के लिए)। नतीजतन मेरे पास रोक है (सर्वर पहले से क्रैश किए गए क्लाइंट को डेटा नहीं भेज सकता है) और इसकी अवधि दुर्घटनाग्रस्त दूरस्थ ग्राहकों की संख्या के समान है। 5 क्रैश किए गए क्लाइंट रुकने के बाद इतने लंबे समय तक कि यह पूरी तरह से सर्वर स्टॉप के बराबर है।

मुझे डीसीओएम "पिंग" तंत्र के बारे में पता है (डीसीओएम को उन ग्राहकों को डिस्कनेक्ट करना चाहिए जो 6 मिनट के चुप्पी के बाद "हर 2 मिनट पिंग" का जवाब नहीं देते हैं)। और वास्तव में, 6 मिनट के लटकने के बाद मेरे पास सामान्य काम की छोटी अवधि होती है लेकिन फिर सर्वर "रुका हुआ" राज्य वापस आ रहा है।

मैं इन सब के साथ क्या कर सकता हूं? डीसीओएम "पिंग" कैसे ठीक काम करता है? अगर मैं अपना खुद का "पिंग" कोड लागू करूंगा तो क्या पुराने डीसीओएम क्लाइंट कनेक्शन को मैन्युअल रूप से डिस्कनेक्ट करना संभव है? यह कैसे करना है?

+0

क्या आपने थ्रेड पूल धागे से घटनाओं को भेजने पर विचार किया है, ताकि अवरोध को सीमित किया जा सके? – bdonlan

+0

@bdonlan: यह एक समाधान हो सकता है, हालांकि यह सर्वर को जटिल रूप से जटिल करेगा - इसे उन अतिरिक्त धागे के जीवनकाल का ख्याल रखना होगा। – sharptooth

+0

वास्तव में नहीं - आप केवल अंतर्निहित Win32 थ्रेड पूल का उपयोग कर सकते हैं। यदि आप पहले से ही एमटीए का उपयोग कर रहे हैं, तो QueueUserWorkItem को हिट करने के लिए यह बहुत छोटा है। यदि आप एसटीए में हैं तो आपको एमटीए में रिमोट इंटरफ़ेस में हैंडल को मार्शल करना होगा, लेकिन CoMarshalInterThreadInterfaceInStream आदि का उपयोग करना अभी भी मुश्किल नहीं है – bdonlan

उत्तर

1

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

ऐसा करने का आसान तरीका QueueUserWorkItem का उपयोग करना है - यह एप्लिकेशन के सिस्टम थ्रेड पूल पर पास कॉलबैक का आह्वान करेगा।

static InfoStruct { 
    IRemoteHost *pRemote; 
    BSTR someData; 
}; 

static DWORD WINAPI InvokeClientAsync(LPVOID lpInfo) { 
    CoInitializeEx(COINIT_MULTITHREADED); 

    InfoStruct *is = (InfoStruct *)lpInfo; 
    is->pRemote->notify(someData); 
    is->pRemote->Release(); 
    SysFreeString(is->someData); 
    delete is; 

    CoUninitialize(); 
    return 0; 
} 

void InvokeClient(IRemoteHost *pRemote, BSTR someData) { 

    InfoStruct *is = new InfoStruct; 
    is->pRemote = pRemote; 
    pRemote->AddRef(); 

    is->someData = SysAllocString(someData); 
    QueueUserWorkItem(InvokeClientAsync, (LPVOID)is, WT_EXECUTELONGFUNCTION); 
} 

अपने मुख्य थ्रेड एक जाँच में है, तो यह केवल थोड़ा और अधिक जटिल है,: यदि आप एक एमटीए का उपयोग कर रहे मान लिया जाये कि, यह सब आप सब करने की ज़रूरत है तुम सिर्फ CoMarshalInterThreadInterfaceInStream और CoGetInterfaceAndReleaseStream उपयोग करने के लिए अपार्टमेंट के बीच इंटरफेस सूचक पारित करने के लिए है:

static InfoStruct { 
    IStream *pMarshalledRemote; 
    BSTR someData; 
}; 

static DWORD WINAPI InvokeClientAsync(LPVOID lpInfo) { 
    CoInitializeEx(COINIT_MULTITHREADED); // can be STA as well 

    InfoStruct *is = (InfoStruct *)lpInfo; 
    IRemoteHost *pRemote; 
    CoGetInterfaceAndReleaseStream(is->pMarshalledRemote, __uuidof(IRemoteHost), (LPVOID *)&pRemote); 

    pRemote->notify(someData); 
    pRemote->Release(); 
    SysFreeString(is->someData); 
    delete is; 

    CoUninitialize(); 

    return 0; 
} 

void InvokeClient(IRemoteHost *pRemote, BSTR someData) { 
    InfoStruct *is = new InfoStruct; 
    CoMarshalInterThreadInterfaceInStream(__uuidof(IRemoteHost), pRemote, &is->pMarshalledRemote); 

    is->someData = SysAllocString(someData); 
    QueueUserWorkItem(InvokeClientAsync, (LPVOID)is, WT_EXECUTELONGFUNCTION); 
} 

ध्यान दें कि त्रुटि जाँच स्पष्टता के लिए elided किया गया है - आप निश्चित रूप से त्रुटि के लिए सभी कॉल की जांच चाहते हैं - विशेष रूप से, आप करना चाहते हैं RPC_S_SERVER_UNAVAILABLE और अन्य ऐसी नेटवर्क त्रुटियों के लिए जांच कर रहे हैं, और अपमानजनक ग्राहकों को हटा दें।

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

0

एक समाधान घटनाओं को खत्म करना होगा - ग्राहकों को सर्वर से पूछताछ करें कि क्या रुचि है या नहीं।

+1

वास्तव में, यह असंभव है। मेरे पास सैकड़ों कार्यक्रम हैं और जितना तेज़ हो सके उतना तेज़ घटना के बारे में क्लाइंट को सूचित करना बहुत महत्वपूर्ण है। यदि क्लाइंट नए कार्यक्रमों के लिए सर्वर से हर 1 सेकंड तक पूछेगा - यह पर्याप्त तेज़ नहीं है। यदि ग्राहक प्रति सेकंड 100 बार सर्वर से पूछेगा - 5 से अधिक ग्राहक पूरी तरह से सर्वर, नेटवर्क और सीपीयू लटकाएंगे। – Ezh

+0

@Ezh: उचित लगता है, लेकिन क्या आपने वास्तव में इसका परीक्षण किया है? कितना तेज़ "कुछ भी नहीं" कॉल निष्पादित करता है? – sharptooth

+1

हां, मैंने परीक्षण किया है। रिमोट डीसीओएम कॉल यह "कुछ भी नहीं" है। यह नेटवर्क संचार, विंडोज सुरक्षा, मार्शलिंग इत्यादि है। कुछ मिलीसेकंड प्लस नेटवर्क और सीपीयू लोड। – Ezh

0

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

0

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

संबंधित मुद्दे