2009-03-03 20 views
7

मुझे पता है, मैं ढेर सारे प्रश्न पूछ रहा हूँ ... लेकिन एक नए डेल्फी डेवलपर के रूप में मैं का उपयोग कर इन सब सवालों :)इंडी लिखें बफरिंग/कुशल टीसीपी संचार

टीसीपी संचार के साथ यह एक सौदों से अधिक गिरने रखना इंडी 10. संचार को कुशल बनाने के लिए, मैं एक क्लाइंट ऑपरेशन अनुरोध को एक बाइट के रूप में कोड करता हूं (अधिकांश परिदृश्यों में पाठ्यक्रम के अन्य डेटा बाइट्स के बाद, लेकिन इस मामले में केवल एक एकल बाइट)। समस्या यह है कि

var Bytes : TBytes; 
... 
SetLength (Bytes, 1); 
Bytes [0] := OpCode; 
FConnection.IOHandler.Write (Bytes, 1); 
ErrorCode := Connection.IOHandler.ReadByte; 

कि बाइट तुरंत नहीं भेजा जाता है (कम से कम सर्वर पर अमल हैंडलर लागू नहीं है) है। अगर मैं '1' को '9' में बदलता हूं उदाहरण के लिए सब कुछ ठीक काम करता है। मैं मान लिया है कि इंडी निवर्तमान बाइट्स बफ़र्स और

FConnection.IOHandler.WriteBufferClose; 

साथ लिखने बफरिंग को निष्क्रिय करने की कोशिश की, लेकिन यह मदद नहीं की। मैं एक बाइट कैसे भेज सकता हूं और यह सुनिश्चित कर सकता हूं कि इसे तुरंत भेज दिया जाए? और - मैं यहां एक और छोटा सवाल जोड़ता हूं - इंडी का उपयोग करके पूर्णांक भेजने का सबसे अच्छा तरीका क्या है? दुर्भाग्य से मैं TIdTCPServer की IOHandler में WriteInteger की तरह समारोह नहीं मिल सकता है ... और

WriteLn (IntToStr (SomeIntVal)) 

मेरे लिए बहुत कुशल नहीं लगता है। क्या इससे कोई फर्क पड़ता है कि क्या मैं एक पंक्ति में एकाधिक लेखन कमांड का उपयोग करता हूं या चीजों को एक बाइट सरणी में पैक करता हूं और उसे एक बार भेजता हूं?

किसी भी उत्तर के लिए धन्यवाद!

संपादित करें: मैंने संकेत दिया कि मैं इंडी 10 का उपयोग कर रहा हूं क्योंकि पढ़ने और लिखने की प्रक्रियाओं के संबंध में बड़े बदलाव होने लगते हैं।

+0

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

+0

यह आदेश एक अपवाद है। अधिकांश कमांड कमांड पैरामीटर के लिए अधिक बाइट्स जोड़ते हैं। मैंने सोचा कि चीजों को जितना संभव हो उतना करीब पैक करना बुरा नहीं हो सकता है। या मैं यहाँ गलत हूँ? – jpfollenius

+0

जब तक आपका पूरा डेटा फ्रेम एक टीसीपी पैकेट में फिट बैठता है, तब तक इसे बहुत अंतर नहीं करना चाहिए। जब टेक्स्ट डिबगिंग की बात आती है तो टेक्स्ट आधारित प्रोटोकॉल ओटीओएच एक बड़ी मदद होती है। – mghie

उत्तर

6

लिखें बफरिंग डिफ़ॉल्ट रूप से अक्षम है। आप fConnection.IOHandler.WriteBufferingActive प्रॉपर्टी का परीक्षण करके यह देखने के लिए लिखने वाले बफरिंग को देख सकते हैं कि यह आपके कोड में सक्रिय है या नहीं।

जहां तक ​​एक पूर्णांक भेजने का सबसे अच्छा तरीका है ... यह आपके प्रोटोकॉल और समग्र लक्ष्यों पर निर्भर करता है। विशेष रूप से, FConnection.IOHandler.Write() का उपयोग करें क्योंकि एक पूर्णांक समेत किसी भी प्रकार के डेटा के बारे में लिखने के लिए अधिभारित विधियां हैं।

IdIOHandler से लिया:

// Optimal Extra Methods 
// 
// These methods are based on the core methods. While they can be 
// overridden, they are so simple that it is rare a more optimal method can 
// be implemented. Because of this they are not overrideable. 
// 
// 
// Write Methods 
// 
// Only the ones that have a hope of being better optimized in descendants 
// have been marked virtual 
procedure Write(const AOut: string; const AEncoding: TIdEncoding = enDefault); overload; virtual; 
procedure WriteLn(const AEncoding: TIdEncoding = enDefault); overload; 
procedure WriteLn(const AOut: string; const AEncoding: TIdEncoding = enDefault); overload; virtual; 
procedure WriteLnRFC(const AOut: string = ''; const AEncoding: TIdEncoding = enDefault); virtual; 
procedure Write(AValue: TStrings; AWriteLinesCount: Boolean = False; const AEncoding: TIdEncoding = enDefault); overload; virtual; 
procedure Write(AValue: Byte); overload; 
procedure Write(AValue: Char; const AEncoding: TIdEncoding = enDefault); overload; 
procedure Write(AValue: LongWord; AConvert: Boolean = True); overload; 
procedure Write(AValue: LongInt; AConvert: Boolean = True); overload; 
procedure Write(AValue: SmallInt; AConvert: Boolean = True); overload; 
procedure Write(AValue: Int64; AConvert: Boolean = True); overload; 
procedure Write(AStream: TStream; ASize: Int64 = 0; AWriteByteCount: Boolean = False); overload; virtual; 

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

एक बहुत ही कठिन उदाहरण के रूप में:

FConnection.IOHandler.Write(myCommand.Serialize()); 
:

TmyCommand = class(TmyProtocol) 
private 
    fCommand:Integer; 
    fParameter:String; 
    fDestinationID:String; 
    fSourceID:String; 
    fWhatever:Integer; 
public 
    property Command:Integer read fCommand write fCommand; 
    ... 

    function Serialize; 
    procedure Deserialize(Packet:String); 
end; 

function TmyCommand.Serialize:String; 
begin 
    //you'll need to delimit these to break them apart on the other side 
    result := AddItem(Command) + 
      AddItem(Parameter) + 
      AddItem(DestinationID) + 
      AddItem(SourceID) + 
      AddItem(Whatever); 
end; 
procedure TMyCommand.Deserialize(Packet:String); 
begin 
    Command := StrToInt(StripOutItem(Packet)); 
    Parameter := StripOutItem(Packet); 
    DesintationID := StripOutItem(Packet); 
    SourceID := StripOutItem(Packet); 
    Whatever := StrToInt(StripOutItem(Packet)); 
end; 

तब के माध्यम से इस भेज

दूसरी तरफ आप इंडी के माध्यम से डेटा और फिर

myCommand.Deserialize(ReceivedData); 
+0

+1 महान जवाब। धन्यवाद! – jpfollenius

+0

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

+0

मेरे लिए संचार में यूनिकोड, और यू.एस. में बहुत सारे लोग उपयोगी से कम हैं। इसके अलावा, मैं टिडबाइट्स की तुलना में क्रमबद्धता के लिए तारों का उपयोग करना चाहता हूं। मैंने कभी भी इंडी 10 का उपयोग किसी भी महत्वपूर्ण के लिए समाप्त नहीं किया है - इंडी 9 अगर इंडी बिल्कुल। –

0

लगता है जैसे आपको अपने बफर को फ्लश करना है। इस प्रयास करें: बफर स्पष्ट करने के

TIdTCPConnection.CancelWriteBuffer; 

मदद के अनुसार, यह पहली कॉल ClearWriteBuffer, और फिर CloseWriteBuffer कॉल:

TIdTCPConnection.FlushWriteBuffer; 

आप एक लिखने बफर नहीं करना चाहते हैं, इस का उपयोग करें।

एक पूर्णांक भेजने के लिए सबसे अच्छा तरीका है (इंडी 10 का प्रयोग करके) TIdIOHandler.Write उपयोग कर रहा है (इंडी 10 मदद लिखें के अनुसार पूर्णांकों सहित विभिन्न प्रकार के डेटा, संभाल करने के लिए ओवरलोड हो गया है)

+0

मैंने बफर को फ्लश करने की कोशिश की, लेकिन यह कोई चीज़ नहीं बदलेगी। कोई भी लिखने वाला बफर नहीं होना चाहिए, क्योंकि WriteBufferClose को कॉल करने से मदद लिखने वाले बफर (जैसे WriteBufferCancel) – jpfollenius

+0

... और WriteInteger के साथ आपके संपादन से संबंधित है: मुझे लगता है कि आप इंडी 9 का उपयोग कर रहे हैं। मेरे IOHandler में शामिल नहीं है ऐसी एक विधि। – jpfollenius

+0

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

4

मैं से परिचित नहीं हूँ इंडी, लेकिन आप (। आप ऐसा ही कुछ के लिए इंडी स्रोत पेड़ grep करना चाह सकते हैं - "देरी" यह क्या करना चाहिए के लिए केस संवेदी) एक TCP_NODELAY विकल्प के लिए अपने एपीआई आसपास देखने के लिए चाहते हो सकता है

संपादित करें: Rob Kennedy इंगित किया कि जिस संपत्ति का मैं जिक्र कर रहा था वह TIdIOHandlerSocket.UseNagle से अधिक है ks!

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

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

+0

आप नागले के बारे में बात कर रहे हैं, है ना? यह इंडी में TIdIOHandlerSocket.UseNagle संपत्ति के साथ नियंत्रित है। –

+0

यूप, नागले - धन्यवाद, रॉब। मैंने तदनुसार पोस्ट संपादित किया है। –

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