การใช้ Delphi เพื่อสร้างเซิร์ฟเวอร์การสื่อสารและการแลกเปลี่ยนข้อมูล - การวิเคราะห์เทคโนโลยีตัวรับส่งสัญญาณ (ตอนที่ 2) ผู้แต่ง: 火鸟 [email protected] 2. คำอธิบายโดยละเอียดของบริการตัวรับส่งสัญญาณ 1. สรุปการวิเคราะห์บริการตัวรับส่งสัญญาณ บริการรับส่งสัญญาณเป็นองค์ประกอบหลักของระบบตัวรับส่งสัญญาณ เคอร์เนลของตัวรับส่งสัญญาณมีหน้าที่ในการอ่านคำจำกัดความและพารามิเตอร์ของพอร์ตและช่องสัญญาณที่ตั้งค่าโดยคอนโซลตัวรับส่งสัญญาณจากไลบรารีการกำหนดค่าระบบ สร้างและควบคุมพอร์ตการสื่อสารแบบไดนามิกและความสัมพันธ์ระหว่างรันไทม์ และการควบคุมข้อมูล การกำหนดเวลาการรับ การส่ง และการบัฟเฟอร์ การจัดการบันทึกและคิว ฯลฯ Transceiver Shell คือการใช้งานพอร์ตทุกประเภทที่รองรับการส่งและรับข้อมูล 2. สรุปการออกแบบบริการตัวรับส่งสัญญาณ บริการตัวรับส่งสัญญาณได้รับการพัฒนาจากแอปพลิเคชันบริการใน Delphi แอปพลิเคชันบริการสามารถทำงานในโหมดระบบแทนโหมดผู้ใช้ได้ และเป็นของโปรแกรมพื้นหลัง เคอร์เนลตัวรับส่งสัญญาณเป็นชุดวิธีการของคลาสตัวรับส่งสัญญาณที่สร้างและควบคุมเชลล์ตัวรับส่งสัญญาณ และตัวรับส่งสัญญาณเชลล์คือชุดของวัตถุที่รับผิดชอบในการสื่อสาร หมายเหตุ: เนื่องจากการพิจารณาประสิทธิภาพและโหลด เคอร์เนลของตัวรับส่งสัญญาณจะใช้เฉพาะการแบ่งการทำงานในไดอะแกรมสถาปัตยกรรมตามตรรกะเท่านั้น และโมดูลที่เป็นส่วนประกอบจะไม่ถูกนำมาใช้ในลักษณะที่อิงตามอ็อบเจ็กต์โดยสมบูรณ์ 3. สรุปการดำเนินการบริการตัวรับส่งสัญญาณ i. สร้างแอปพลิเคชันบริการ เลือก ใหม่|อื่นๆ... จากเมนูหลัก Delphi ไฟล์... และเลือก ใหม่|แอปพลิเคชันบริการ ในกล่องโต้ตอบรายการใหม่แบบผุดขึ้น คุณจะเห็นว่าโปรแกรมที่สร้างขึ้น กรอบงานเป็นดังนี้: PROgram Project1; ใช้ SvcMgr, Unit1 ใน 'Unit1.pas' {Service1: TService}; {$R *.RES}begin Application.Initialize; Application.CreateForm(TService1, Service1); Application.Run;end.unit Unit1;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs;type TService1 = class(TService) private { การประกาศส่วนตัว } public function GetServiceController: TServiceController; { Public declarations } end;var Service1: TService1;ขั้นตอนการดำเนินการ {$R *.DFM} ServiceController (CtrlCode: DWord); stdcall; เริ่ม Service1.Controller (CtrlCode); end; ฟังก์ชั่น TService1.GetServiceController: TServiceController; เริ่มต้นผลลัพธ์ := ServiceController;end;end คุณจะเห็นว่านอกเหนือจาก SvcMgr ที่ใช้สำหรับการจัดการบริการที่อ้างอิงในหน่วยการใช้งานแล้ว TService1 ยังสืบทอดจาก TServiced แทน TForm ซึ่งเป็นฟังก์ชัน GetServiceController ที่โอเวอร์โหลดและกระบวนการ ServiceController ที่ถูกเรียกในโหมด stdcall มันถูกสร้างขึ้นด้วย Delphi โปรแกรมการบริการไม่มีอะไรพิเศษมากนัก แฟนๆ Delphi อาจจะอยากกลับมาเชียร์อีกครั้ง นี่คือเสน่ห์อันทรงพลังของ Delphi RAD นอกจากนี้ เนื่องจากแอปพลิเคชันบริการไม่สามารถดีบั๊กได้โดยตรงที่รันไทม์ และไม่มีอินเทอร์เฟซผู้ใช้ จึงควรพิจารณาเอาต์พุตข้อมูลการดีบักแบบไร้อินเทอร์เฟซในระหว่างการพัฒนา เพื่ออำนวยความสะดวกในการดีบักและการแก้ไขปัญหา ii. ในการสร้างคลาสพอร์ตที่ตรงกับความต้องการเฉพาะและใช้เคอร์เนลตัวรับส่งสัญญาณที่มีกลไกการทำงานและการประมวลผลแบบครบวงจร พอร์ตในเชลล์ตัวรับส่งสัญญาณจะต้องมีกฎการประมวลผลแบบรวมศูนย์บางพอร์ตในเชลล์นั้นเป็นคลาสส่วนประกอบที่มีอยู่ใน Delphi สภาพแวดล้อมการพัฒนา (เช่น TCP, FTP เป็นต้น) และบางส่วนไม่ใช่ (เช่น MSMQ, File เป็นต้น) ในเวลานี้ คุณต้องสร้างคลาสที่สามารถตอบสนองความต้องการของคุณได้ ตัวอย่างเช่น: type//เนื่องจากไม่มีอินเทอร์เฟซผู้ใช้ จึงสืบทอดมาจาก TComponent แทน TControl TFilePort=class(TComponent) private FilePath:string;//รับหรือบันทึกตำแหน่งโฟลเดอร์ของไฟล์ Prefix:string;//File คำต่อท้ายคำต่อท้าย: string; // ส่วนต่อท้ายไฟล์; หลังจากสร้างคลาส TFilePort แล้ว Kernel ตัวรับส่งสัญญาณสามารถใช้วิธีการประมวลผลคลาสแบบรวมเพื่ออ้างอิงและจัดการวัตถุเพื่อให้บรรลุวัตถุประสงค์ในการเข้าถึงไฟล์เฉพาะจากโฟลเดอร์ที่ระบุโดย FilePath หากใช้เป็นแหล่งที่มา ไฟล์ที่ตรงตามเงื่อนไขจะได้รับจากโฟลเดอร์เฉพาะ หากใช้เป็นเป้าหมาย ข้อมูลที่ได้รับจากแหล่งที่มาที่เกี่ยวข้องจะถูกเขียนไปยังไฟล์ที่ระบุ (อันที่จริงแล้ว พารามิเตอร์ที่แท้จริงของแต่ละออบเจ็กต์พอร์ตมาจาก คำจำกัดความของตารางพอร์ตในไลบรารีการกำหนดค่าระบบ) อีกตัวอย่างหนึ่ง: พิมพ์ TCOMPort=class(TComponent) อินเทอร์เฟซ ComFace:string;//COM เพื่อรับหรือส่งข้อมูล TCOMPort จะถูกใช้เพื่อรับข้อมูลจากหรือส่งข้อมูลไปยังอินเทอร์เฟซคอมโพเนนต์ COM ที่ระบุ ใน Delphi คลาส OleVariant เป็นหนึ่งในวิธีในการใช้การเรียกคอมโพเนนต์ COM ความจำเป็นในการใช้คลาส TCOMPort คือตัวรับส่งสัญญาณจะสร้างอินสแตนซ์อินเทอร์เฟซ COM ที่กำหนดโดย TCOMPort ลงในวัตถุ OleVariant เฉพาะเมื่อจำเป็นต้องมีการเข้าถึงข้อมูลเท่านั้น และวัตถุนั้น จะถูกปล่อยออกมาหลังการใช้งาน ซึ่งสามารถลดแรงกดดันในการรับส่งสัญญาณและเซิร์ฟเวอร์ COM ข้อควรพิจารณาเดียวกันนี้ใช้กับส่วนประกอบอื่นๆ ที่คล้ายคลึงกัน ตัวอย่างชั้นเรียนที่ผู้เขียนจัดทำไว้ที่นี่เป็นเพียงแบบจำลอง และควรเพิ่มวิธีการและเหตุการณ์ที่เหมาะสมเมื่อจำเป็น คลาสที่ผู้เขียนนำมาใช้ระหว่างการพัฒนา ได้แก่: TCOMPort, TMSMQPort, TDBPort, TFilePort ฯลฯ รองรับหลายช่องสัญญาณ - อาร์เรย์ของวัตถุที่ประกาศพอร์ต ตัวรับส่งสัญญาณถือว่ากระบวนการสื่อสารเป็นกระบวนการไหลข้อมูลจากแหล่งหนึ่งไปยังอีกเป้าหมายหนึ่ง กระบวนการดังกล่าวคือช่องหนึ่งในตัวรับส่งสัญญาณ และช่องสัญญาณนี้ประกอบด้วยอย่างน้อยสองช่อง ประกอบด้วยสองช่อง พอร์ต (หนึ่งพอร์ตสำหรับต้นทางและอีกพอร์ตสำหรับเป้าหมาย) ดังนั้นหากคุณต้องการกำหนดจำนวนแชแนลที่สามารถรวมเข้ากับแหล่งที่มาและเป้าหมายได้อย่างอิสระ คุณต้องประกาศแยกกันสำหรับแหล่งที่มาและเป้าหมาย อาร์เรย์ของออบเจ็กต์ของคลาสพอร์ตต่างๆ (และสร้างความสัมพันธ์ที่สอดคล้องกันสำหรับคลาสเหล่านั้น ดังที่คุณจะเห็นในภายหลัง) ตัวอย่างเช่น: ส่วนตัว { การประกาศส่วนตัว }TCPSource:array of TServerSocket;//Object array for TCP Source TCPTarget:array of TClientSocket;//Object array for TCP Target MailSource:array of TIdPOP3; //For Mail Source Object array MailTarget:array ของ TIdSMTP; // อาร์เรย์วัตถุสำหรับไฟล์เป้าหมายเมล: อาร์เรย์ของ TFilePort; //อาร์เรย์วัตถุสำหรับแฟ้มแหล่งที่มา fileTarget:อาร์เรย์ของ TCOMPort; //สำหรับอาร์เรย์วัตถุเป้าหมาย COM หมายเหตุ: เนื่องจาก กฎการทำงานของพอร์ตสำหรับแหล่งที่มาและเป้าหมายประเภทเดียวกันนั้นแตกต่างกันโดยสิ้นเชิง ซึ่งถือเป็นวัตถุที่แตกต่างกันโดยสิ้นเชิงโดยไม่มีความสัมพันธ์โดยตรงในแนวคิดตัวรับส่งสัญญาณ ดังนั้นสำหรับพอร์ตประเภทเดียวกัน อาร์เรย์ออบเจ็กต์จะถูกสร้างขึ้นแยกจากกันตามแหล่งที่มาและเป้าหมาย iv. สร้างอินสแตนซ์ของอาร์เรย์ออบเจ็กต์ ณ รันไทม์ จำนวนองค์ประกอบในแต่ละออบเจ็กต์ได้รับการจัดการโดย Port Builder เมื่อรันไทม์ หากผู้ใช้กำหนดพอร์ตบางประเภทผ่านคอนโซลตัวรับส่งสัญญาณ ตัวสร้างพอร์ตจะสร้างอินสแตนซ์ตามหมายเลขของพวกเขา และพารามิเตอร์ตามลำดับ มิฉะนั้นอาร์เรย์วัตถุจะไม่ถูกสร้างอินสแตนซ์ ในออบเจ็กต์พอร์ตประเภทแหล่งที่มา คุณสมบัติชื่อจะถูกตั้งค่าเป็นรูปแบบ 'รับ'+รหัสพอร์ต ในทริกเกอร์การรับข้อมูลที่ตามมา สิ่งนี้จะช่วยให้ Data Dispatcher ค้นหาออบเจ็กต์และกำหนดเวลาออบเจ็กต์พอร์ตประเภทต่างๆ อย่างสม่ำเสมอ แอตทริบิวต์แท็กใช้เพื่อให้ข้อมูล ID เป้าหมายของช่องที่ช่องนั้นตั้งอยู่แก่ตัวควบคุมช่องสัญญาณ ต่อไปนี้เป็นส่วนการสร้างอินสแตนซ์ของอาร์เรย์อ็อบเจ็กต์ comSource ใน Port Builder start //Create COM/ Receiver Port itmp:=high(comSource)+1;// รับจำนวน comSource สูงสุดในปัจจุบัน โดย itmp เป็นตัวแปรจำนวนเต็ม SetLength(comSource ,itmp +1); // เพิ่มสมาชิกอาร์เรย์ comSource comSource [itmp]:=TCOMPort.Create(self); // สร้างอินสแตนซ์สมาชิก comSource[itmp].Name:= 'Receive'+inttostr(isource); //ตั้งค่าแอตทริบิวต์ Name เป็น 'Receive'+Port ID และ isource คือ PortID ปัจจุบันของประเภทจำนวนเต็ม comSource [itmp].Tag:= itarget; //ตั้งค่าเป็นเป้าหมาย ID ของ Channel ที่มันตั้งอยู่ NullTest :=rece.Fields['Address'].value;// รับค่าของการกำหนดค่าระบบ COMFace, NullTest เป็นตัวแปร Variant ถ้า (NullTest <>null) และ (ตัดแต่ง(NullTest)<>'') จากนั้น startcomSource [itmp].ComFace:=NullTest; //กำหนดค่าที่ถูกต้องให้กับ ComFaceNullTest:=rece.Fields['interval'].value; // รับช่วงเวลาทริกเกอร์สำหรับวัตถุ COM เพื่อรับข้อมูลในการกำหนดค่าระบบ SetTimer(application.handle,isource,NullTest*60000 ,ไม่มี); //สร้างนาฬิกาทริกเกอร์สำหรับพอร์ตปัจจุบันเพื่อรวบรวมข้อมูลอย่างสม่ำเสมอ isource คือพอร์ต IDendelsecomSource [itmp].Tag:=-1;//การเริ่มต้นล้มเหลว ทำเครื่องหมายว่าสิ้นสุดพอร์ตที่ไม่ถูกต้อง; comSource คือพอร์ตคลาสต้นทางที่ใช้ในการเรียกอินเทอร์เฟซที่กำหนดใน ComFace และรับข้อมูลหลังจากช่วงเวลาหนึ่ง ซึ่งสอดคล้องกับ comTarget การใช้งานคือ คล้ายกัน ยกเว้นว่าการส่งข้อมูลไปยัง ComFace ของ comTarget นั้นเป็นกระบวนการแบบเรียลไทม์ ดังนั้นจึงไม่จำเป็นต้องใช้ช่วงทริกเกอร์ และสามารถละเว้นสองคำสั่งในการสร้างนาฬิกาได้ การสร้างและการเริ่มต้นของออบเจ็กต์ Port ประเภทอื่นจะคล้ายกัน ตัวอย่างเช่น ส่วนการใช้งาน MailTarget อื่น: start //Create SMTP/Send Port itmp:=high(MailTarget)+1; SetLength(MailTarget,itmp+1); MailTarget[itmp]:=TIdSMTP.Create(self); itmp].ชื่อ:='ส่ง'+ inttostr(itarget); MailTarget[itmp].Tag:=3;//ตั้งเป็นการระบุประเภทพอร์ตเป้าหมาย NullTest:=rece.Fields['Address'].value; // ที่อยู่เซิร์ฟเวอร์เมลถ้า (NullTest <>null) และ (trim(NullTest) <>'') จากนั้น MailTarget[itmp].Host :=NullTest else bValid:=false; NullTest:=rece.Fields['Port'].value; //Mail server port ถ้า NullTest <>null แล้ว (ถ้า NullTest<>0 แล้ว MailTarget[itmp].Port :=NullTest)else bValid:=false; =rece.Fields['user'].value;//ชื่อผู้ใช้เข้าสู่ระบบหาก NullTest <>null thenMailTarget[itmp].UserId :=NullTest else bValid:=false; NullTest:=rece.Fields['password'].value;//รหัสผ่านเข้าสู่ระบบ………………end;บางทีคุณอาจจะมีบางอย่างเช่น ฉันมีข้อสงสัยบางประการ ส่วนประกอบการสื่อสาร Transceiver Shell จำนวนมากถูกสร้างขึ้นโดย Port Builder ณ รันไทม์ ประสิทธิภาพของบริการ Transceiver จะสูงหรือไม่ ในความเป็นจริง ภารกิจของ Port Builder จะเสร็จสิ้นเมื่อมีการเหตุการณ์ ServiceCreate เกิดขึ้น จำนวน Shell Ports จะส่งผลต่อความเร็วในการเริ่มต้นของ Transceiver Service เท่านั้น ไม่ได้รับผลกระทบแน่นอนทรัพยากรระบบอาจจะกินเวลาเพิ่มอีกนิดหน่อย v. การจัดสรรแบบไดนามิกและการประมวลผลเหตุการณ์ในพอร์ตการสื่อสารหลายพอร์ตที่รองรับโดย Transceiver Shell ให้ใช้ TServerSocket (คุณอาจต้องการใช้ส่วนประกอบการสื่อสารของ Indy แต่สิ่งนี้ไม่ได้ละเมิดแนวคิดการออกแบบของ Transceiver Service มันเป็นเพียงการแก้ไขที่ ระดับเชลล์ (หรือเพิ่งเพิ่ม) TCPSource ที่ใช้งานนั้นมีความโดดเด่นมากกว่า เนื่องจาก TServerSocket ซึ่งเป็นพอร์ตต้นทางนั้นแตกต่างจากออบเจ็กต์เช่น COM หรือ POP3 ที่ต้องถูกทริกเกอร์เป็นประจำ บริการจะอยู่ในสถานะการรับฟังเสมอหลังจากเริ่มต้นแล้ว เป็นส่วนประกอบที่สร้างเหตุการณ์ที่สอดคล้องกันเมื่อ ClientSocket เชื่อมต่อและส่งข้อมูล ต่อไปนี้เป็นส่วนอินสแตนซ์ของ TCPSource: start //Create TCP/Receive Port itmp:=high(TCPSource)+1;SetLength(TCPSource,itmp+1); TCPSource [itmp]:=TServerSocket.Create(self); [ itmp].OnClientRead:=TCPServersClientRead;//กำหนดกระบวนการประมวลผลของเหตุการณ์ OnClientRead ให้กับ TCPServersClientRead TCPSource [itmp].OnClientError:=TCPServerClientError;//กำหนดกระบวนการประมวลผลของเหตุการณ์ OnClientError ให้กับ TCPServerClientErrorTCPSource [itmp].Name:= 'Receive'+inttostr(isource); // ตั้งค่าคุณสมบัติ Name เป็น 'Receive'+Port ID TCPSource [itmp ].Tag:=itarget; //ตั้งค่า IDTCPSource เป้าหมายของ Channel [itmp].Socket.Data:=@ TCPSource [itmp].Tag;//แนบ ID เป้าหมายของออบเจ็กต์ Port นี้กับออบเจ็กต์ Socket เพื่อเป็นข้อมูลชี้………………สิ้นสุด; กลับมาดูการประมวลผลของ comSource ของเราในระหว่างการสร้างอินสแตนซ์ มันสร้างนาฬิกาทริกเกอร์ แต่จะจัดการกับเหตุการณ์เมื่อนาฬิกาทริกเกอร์ได้อย่างไร? ในทำนองเดียวกัน เป็นการจัดสรรแบบไดนามิกของการประมวลผลเหตุการณ์ด้วย คุณสามารถเพิ่มคำจำกัดความการประมวลผลของนาฬิกาของ comSource ลงในการประมวลผลเหตุการณ์ ServiceCreate: application.OnMessage:=Timer; เพื่อใช้การประมวลผลข้อความมากเกินไป เมื่อมีการสร้างข้อความจากแอปพลิเคชัน Timer จะถูกทริกเกอร์ ในเหตุการณ์ Timer กรองการประมวลผล ด้วยข้อความ WM_TIMER ที่ทริกเกอร์โดยนาฬิกา คุณสามารถเรียกวิธีการเก็บข้อมูลของพอร์ตต้นทางเฉพาะตามรหัสพอร์ตและประเภท: Procedure TCarrier.Timer(var Msg: TMsg; var Handled: Boolean);var stmp:string; Obj:TComponent;begin if Msg.message =WM_TIMER จากนั้น//การประมวลผลข้อความนาฬิกาเริ่มต้น//ค้นหาวัตถุที่กำหนดข้อความนี้ตามรหัสพอร์ตที่ทริกเกอร์ messageObj:=FindComponent(' รับ '+inttostr (Msg.WParam)); ถ้า obj=nil แล้วออก;//ออกจากการประมวลผลหากไม่พบ stmp:=obj.ClassName;//สะท้อนกลับเพื่อรับข้อมูลประเภทของวัตถุพอร์ตนี้ถ้า stmp='TIdPOP3' แล้ว GetPOP3(TIdPOP3(Obj)); ถ้า stmp='TIdFTP' แล้ว GetFTP(TIdFTP(obj)); ถ้า stmp='TFilePort' แล้ว GetFile(TFilePort(Obj)); แล้ว GetCOM(TCOMPort(Obj));//เรียกกระบวนการรับข้อมูลของ COMSource…………………… end;end; vi. รับข้อมูล ต่อไปนี้เป็นขั้นตอนการประมวลผลการรับข้อมูลของ COMSource TCarrier.GetCOM(COMObj: TCOMPort);var stmp:string; COMInterface:OleVariant;begin try//สร้างวัตถุคอมโพเนนต์ COM ตามค่าของ ComFace COMInterface:=CreateOleObject (COMObj.ComFace); stmp:=COMInterface.GetData; //เรียกวิธีอินเทอร์เฟซที่ตกลงกันไว้เพื่อรับข้อมูลในขณะที่ stmp<>#0 do // #0 คือแฟล็กสิ้นสุดการแยกข้อมูลที่ตกลงไว้ เริ่มต้น DataArrive(stmp, COMObj.Tag); // ส่งมอบให้กับ data Dispatcher สำหรับการประมวลผลแบบรวมศูนย์ COMObj.Tag คือ Target Port ID ของ Channel ที่วัตถุนั้นตั้งอยู่ stmp:=COMInterface.GetData; end ; COMInterface:= ไม่ได้รับมอบหมาย; ยกเว้น COMInterface:= ไม่ได้รับมอบหมาย; ดำเนินการแยกข้อมูลให้เสร็จสมบูรณ์และปล่อยออบเจ็กต์คอมโพเนนต์จนกว่าจะมีการเรียกทริกเกอร์ครั้งต่อไป ต่อไปนี้คือการประมวลผลการรับข้อมูลของ TCPSource: ขั้นตอน TCarrier.TCPServersClientRead(Sender: TObject; Socket:TCustomWinSocket);beginDataArrive(socket.ReceiveText,integer(TServerWinSocket( sender).data ^));//ปล่อยทิ้งไว้ที่ data Dispatcher สำหรับการประมวลผลแบบรวมศูนย์ พารามิเตอร์ที่สองคือค่าตัวชี้ ID พอร์ตเป้าหมายที่แนบมากับผู้ส่งออบเจ็กต์ซ็อกเก็ต สิ้นสุด ออบเจ็กต์ Source Port ประเภทต่างๆ ได้รับข้อมูลในรูปแบบที่แตกต่างกัน แต่ท้ายที่สุดแล้วข้อมูลที่ได้รับจะถูกส่งไปยัง Data Dispatcher จากระดับการใช้งาน ทุกครั้งที่มีการเพิ่มออบเจ็กต์การรับข้อมูลและมีการใช้การรับข้อมูล พอร์ตต้นทางใหม่จะถูกใช้งานสำหรับ Transceiver Shell หมายเหตุ: ผู้เขียนใช้เฉพาะการรับข้อมูลข้อความเท่านั้น ผู้ใช้อาจจำเป็นต้องรับออบเจ็กต์หน่วยความจำ สตรีมข้อมูล หรือข้อมูลไบนารี และเพียงทำการเปลี่ยนแปลงเล็กน้อยกับโค้ดรับ vii การกำหนดเวลาข้อมูล การกำหนดเวลาข้อมูลของบริการ Transceiver เสร็จสมบูรณ์โดยหน่วยโลจิคัล Data Dispatcher ภารกิจหลักของ Data Dispatcher คือการจัดการและควบคุมข้อมูลที่ได้รับจากพอร์ตต้นทางต่างๆ อย่างสม่ำเสมอ และทำงานร่วมกับ Channel Controller ตาม Channel Define การกระจายข้อมูลไปยังพอร์ตเป้าหมายต่างๆ ให้ตรวจสอบว่าผลลัพธ์การส่งสำเร็จหรือไม่ และตัดสินใจว่าจำเป็นต้องส่งข้อมูลไปยัง Queue Manager และ Log Recorder สำหรับการบัฟเฟอร์และการประมวลผลบันทึกตามผลลัพธ์การส่งและการตั้งค่า ของไลบรารีการกำหนดค่าระบบ จากนั้น ดูที่วิธี DataArrive ของ Source Port ที่ส่งข้อมูล: ขั้นตอน TCarrier.DataArrive(sData:String;PortID:Integer);var dTime:Datetime; bSendSeccess:Boolean;begin if sData='' then exit;/ / หากข้อมูลว่างเปล่า ให้ข้าม iLogID:=-1; dTime:= now; //Receive time if sData[length(sdata)]=#0 then sdata:=copy(sdata,1,length(sdata)-1);//รูปแบบสตริงสำหรับความเข้ากันได้ของภาษา C bSendSeccess:=DataSend(sdata,PortID);//Call Data Dispatcher เพื่อส่งวิธีการจัดส่ง PortID คือ Target Port IDif (TSCfg.LogOnlyError=false) หรือ (bSendSeccess=false) theniLogID:=writeLog(dTime, ตอนนี้, sData, PortID, bSendSeccess);//บันทึกบันทึกตามกฎการประมวลผลบันทึกและส่งผลลัพธ์ในข้อมูลการกำหนดค่าระบบหาก (TSCfg.Queueing=True) และ (bSendSeccess=false) จากนั้นใส่ PutQueue(dTime, now,sData, PortID, bSendSeccess, iLogID) ; / /กำหนดสิ้นสุดการประมวลผลคิวตามข้อกำหนดการกำหนดค่าคิวในข้อมูลการกำหนดค่าระบบแพ็กเกจ ข้างต้นคือข้อมูล วิธี DataArrive ของผู้จัดส่ง ซึ่งการประมวลผลคิวถูกกำหนดตามข้อมูลการกำหนดค่าระบบและสถานะการส่ง นอกจากนี้ยังสามารถปรับเป็นการประมวลผลคิวบังคับได้อีกด้วย ต่อไปนี้คือเมธอด DataSend ของ Data Dispatcher ซึ่งใช้ในการกระจายและประมวลผลข้อมูลตามประเภทพอร์ตเป้าหมาย: Function TCarrier.DataSend(sData:String;PortID:Integer):boolean;var Obj:TComponent;begin DataSend:= false;Obj:=FindComponent ('ส่ง'+inttostr(PortID)); //ค้นหาวัตถุตามรหัสพอร์ตถ้า (obj=nil) หรือ (obj.Tag =-1) จากนั้นออก;//ไม่มีวัตถุหรือถูกทำเครื่องหมายว่าไม่ถูกต้องเนื่องจากความล้มเหลวในการเริ่มต้น obj.Tag ของ 1:DataSend:=PutTCP(TClientSocket(obj),sdata); 3:DataSend:=PutSMTP(TIdSMTP (obj), sdata); 5:DataSend:=PutFTP(TIdFTP(obj),sdata); 7:DataSend:=PutHTTP(TIdHTTP(obj),sdata); 9:DataSend:=PutFile(TFilePort(obj),sdata); 11:DataSend:=PutMSMQ(TMSMQPort (obj),sdata); PutDB(TDBPort(obj),sdata); 15:DataSend:=PutCOM(TCOMPort (obj),sdata); …… …… end;end; เป็นที่น่าสังเกตว่าหากไม่ได้ใช้อาร์เรย์วัตถุ แต่มีเพียงอินสแตนซ์เดียวเท่านั้น ประเภทของพอร์ต หากเป็นเช่นนั้น วิธีที่ดีกว่าในการจัดการการกระจายข้อมูลคือการใช้ฟังก์ชันเรียกกลับ แต่ในกรณีปัจจุบัน นั่นจะทำให้ไม่รู้ว่าสมาชิกของอาร์เรย์วัตถุตัวใดควรจัดการข้อมูล นอกจากนี้ วิธีการประมวลผลในปัจจุบันไม่ได้แยก Transceiver Kernel และ Transceiver Shell อย่างสมบูรณ์ และเราควรหาวิธีการประมวลผลที่เป็นนามธรรมและเป็นอิสระมากขึ้น viii. การส่งข้อมูล ต่อไปนี้เป็นฟังก์ชันการส่งของ TCP TCarrier.PutTCP(TCPOBJ:TClientSocket;sdata:string):Boolean;var itime:integer;begin PutTCP:=false; try TCPOBJ.Open; gettickcount; //เริ่มต้นแอปพลิเคชันซ้ำ ProcessMessages; จนถึง (TCPOBJ.Active=true) หรือ (gettickcount-itime>5000); //กระโดดออกจากลูปหากการเชื่อมต่อสำเร็จหรือเกิดการหมดเวลา 5 วินาทีหาก TCPOBJ.Active จากนั้นเริ่ม TCPOBJ.Socket.SendText(sdata); ค่าที่ส่งคืนจะเกิดขึ้นเมื่อส่งข้อมูลสำเร็จเท่านั้น Trueend;TCPOBJ.Close; ExceptTCPOBJ.Close; end;The following is the sending function of COM TCarrier.PutCOM(COMOBJ:TCOMPort;sdata:string):Boolean;var Com:OleVariant;begin PutCOM:=false; ลอง Com:=CreateOleObject(COMOBJ.ComFace);//สร้างอินเทอร์เฟซที่กำหนดไว้ล่วงหน้า PutCOM:=Com.PutData ( sdata);//เรียกเมธอดที่กำหนดไว้ล่วงหน้า Com:= Unassigned; end; การส่งพอร์ตประเภทอื่นจะคล้ายกันและจะไม่ทำซ้ำที่นี่ จนถึงขณะนี้ การประมวลผลพื้นฐานของแหล่งที่มาและเป้าหมายได้เสร็จสิ้นแล้ว มีการสร้างฟังก์ชันการสื่อสารขั้นพื้นฐานขึ้น หลังจากจับคู่แหล่งที่มาและเป้าหมายประเภทต่างๆ ได้ฟรี ฟังก์ชันการสื่อสารที่แตกต่างกันโดยสิ้นเชิงจึงสามารถเกิดขึ้นได้ ด้วยการสร้างหลายช่องทาง คุณสามารถใช้การประมวลผลการสื่อสารจากส่วนกลางสำหรับฟังก์ชันต่างๆ ที่หลากหลายได้ ix. การประมวลผลคิว: หลังจากที่ข้อมูลถูกส่งในวิธี DataArrive ข้างต้นแล้ว Data Dispatcher จะเรียกใช้ writeLog สำหรับการบันทึกข้อมูล และวิธี PutQueue สำหรับการประมวลผลคิว พารามิเตอร์ของระบบ พื้นที่เก็บข้อมูลไม่ใช่จุดเน้นของบทความนี้ การประมวลผลคิวซ้ำนั้นคล้ายคลึงกับหลักการกระจายการประมวลผลตามประเภทพอร์ตในเหตุการณ์ Timer โดยอาศัยทริกเกอร์ของ Queue Timer เพื่ออ่านข้อมูลที่บัฟเฟอร์จากฐานข้อมูลและเรียก DataSend อีกครั้งตาม Target Port ID เพื่อ ลองส่งข้อมูลอีกครั้ง หากการส่งข้อมูลสำเร็จ ธุรกรรมการส่งข้อมูลนี้จะเสร็จสมบูรณ์ ไม่เช่นนั้นจะเข้าสู่คิวอีกครั้งและรอเวลาทริกเกอร์ครั้งถัดไปเพื่อลองอีกครั้งจนกว่าการส่งข้อมูลจะสำเร็จหรือตามจำนวนครั้งสูงสุดที่ตั้งไว้ ถึงแล้ว สาม, สรุปประสบการณ์การพัฒนา เนื่องจากจุดเน้นของบทความนี้คือการอธิบายแนวคิดหลักและแนวคิดการออกแบบของ Transceiver จึงช่วยลดความซับซ้อนและลดความยุ่งยากในการประมวลผลแบบ multi-threading การรวมอ็อบเจ็กต์ และการสนับสนุนธุรกรรมที่ Transceiver ควรพิจารณาเป็นบริการเบื้องหลัง และยิ่งซับซ้อนมากขึ้น และการจัดการแหล่งที่มาและกลุ่มเป้าหมายที่มีประสิทธิภาพและชะอำ การรวม nnel ความสามารถในการส่งและรับออบเจ็กต์หน่วยความจำ สตรีมข้อมูล ข้อมูลไบนารี การอ่านข้อมูลการกำหนดค่าระบบและการใช้งานคลาสการห่อหุ้ม ความปลอดภัยของระบบและข้อมูล ฯลฯ ฉันหวังว่าผู้อ่านจะสามารถให้ข้อมูลเชิงลึกและ เข้าใจแนวคิดการออกแบบ Transceiver จุดประกายแรงบันดาลใจในการพัฒนางานจริงและสร้างซอฟต์แวร์ที่โดดเด่นและทรงพลังยิ่งขึ้น ผู้แต่ง: Firebird [email protected] ใช้ Delphi เพื่อสร้างเซิร์ฟเวอร์การสื่อสารและการแลกเปลี่ยนข้อมูล—การวิเคราะห์ทางเทคนิคของตัวรับส่งสัญญาณ (ตอนที่ 1) ใช้ Delphi เพื่อสร้างเซิร์ฟเวอร์การสื่อสารและการแลกเปลี่ยนข้อมูล—การวิเคราะห์ทางเทคนิคของตัวรับส่งสัญญาณ (ตอนที่ 2) ใช้คลาสคอลเลกชันผ่าน C# ภาพรวมของ . คอลเลกชัน NET และ สิ่งทางเทคนิคเก่าที่เกี่ยวข้อง: ทางลัดของโปรแกรม/การลบโปรแกรม/EXE การลบ สิ่งเก่า DIY ด้วยตนเอง: บันทึกประสบการณ์อัลกอริทึมการเขียนโปรแกรมในวัยเด็ก