Establish communication and data exchange servers with Delphi - TRANSCEIVER technology (below)

zhaozj2021-02-17  55

use

Delphi

Establish communication and data exchange servers -

TRANSCEIVER technology analysis (below)

Author: Firebird

Redbirdli@hotmail.com

Second, ????????? TRANSCEIVER SERVICE

1. Transceiver Service Analysis Summary

Transceiver Service is the core composition of the Transceiver system. Transceiver Kernel is responsible for reading Transceiver Console settings from the system configuration library, Channel Definitions and Parameters, Runtime Dynamic Creation and Management of Ports and Its Association, and the data. The buffer is scheduled, and the log, queue is managed. The Transceiver Shell is the implementation of all types of ports that are used for data transceivers.

2. Transceiver Service Design Summary

The Transceiver Service is developed by Service Application in Delphi. Service Application can run in system state rather than user state, and the operating system Service Control Manager (SCM) is responsible for running management, service does not have a user interface, belonging to the system's background program. Transceiver Kernel is a series of methods for building and controlling Transceiver Shell, while Transceiver Shell is a collection of objects responsible for communication.

Note: Due to performance and load considerations, Transceiver Kernel is simplified from a logically implementation of functionality, and constitutes a module and is not implemented in full object.

3. Transceiver Service Implementation Summary

???????????????????????i. ????????????? build a service application

Select New | Other ... From the Delphi Main Menu File Select New | Service Application in the New Items dialog box that pops up, you can see the generated program framework as follows:

PROGRAM Project1;

Uses

? SVCMGR,

• Unit1 in 'unit1.pas' {service1: tService};

{$ R * .res}

Begin

? Application.INITIALIZE;

? Application.createform (TService1, Service1);

Application.run;

End.

?

?

Unit unit1;

Interface

Uses

WINDOWS, Messages, Sysutils, Classes, Graphics, Controls, SVCMGR, DIALOGS

Type

? TService1 = Class (TSERVICE)

? private

??? {private declarations}

? public

??? Function GetServiceController: TServiceController; Override;

??? {public declarations}

? End;

VAR

Service1: TService1;

IMPLEMENTATION

{$ R * .dfm}

Procedure ServiceController (Ctrlcode: DWORD); stdcall;

Begin

Service1.Controller (Ctrlcode);

END;

Function TService1.getServiceController: TServiceController;

Begin

? Result: = serviceController; end;

End.

It can be seen that in addition to the SVCMGR, TService1 inheritable from TSERVICED, TFORM and a heavy-duty GetServiceController function and the serviceController process called in stdcall, not too much. In terms of special, Delphi Fans may cheer, this is the powerful charm of Delphi Rad. In addition, Service Application should consider debugging information when it is not possible to debug directly at runtime, and should be considered when developing.

????????????????????? II. ????????????

To use the Transceiver Kernel that runs a running processor, you will require port in the Transceiver Shell to have a uniform processing rule. Some ports in the shell are the components classes (such as TCP, FTP, etc.) in the Delphi development environment, and some are not ( Such as MSMQ, FILE, etc., you need to create a class that can meet the needs you can do. Such as:

Type // Due to the no user interface, inherit from Tcomponent instead of TControl

?? TfilePort = Class (Tcomponent)

?? private

?????? filepath: string; // Get or save the file folder location

?????? prefix: string; // File prefix

?????? suffix: string; // file suffix

?? End;

After establishing the TFilePort class, Transceiver Kernel can use a unified class handle to reference and manage objects to reach the purpose of accessing a specific file under the folder specified by FilePath. If you are used for Source (Source), you will get the file that meets the condition from a specific folder. If you are used for the Target, the data obtained from the corresponding source (SOURCE) will be written to the specified file (in fact The actual parameters of each port object are derived from the definition of the PORT table in the system configuration library).

another example:

Type

?? Tcomport = Class (Tcomponent)

?? private

?????? comface: String; // Get or submit data COM interface

?? End;

TCOMPORT will be used to obtain subsequent processing from the specified COM component interface or submit data to the specified COM component interface. In Delphi, the Olevariant class is one of the ways to implement COM component calls. The need to use the Tcomport class is that Transceiver will instantiate the TCOMPORT COM interface to Olevariant objects when necessary, and release the object. This reduces the load pressure of Transceiver and COM servers. Other similar components also have the same consideration. Examples of the author here are just a model, and appropriate methods and events should be added if necessary. The class implemented in the development of the author is: Tcomport, TMSMQPort, TDBPORT, TFILEPORT, etc.

????????????????????????????????????????? Multi-Channel support - Declaration Port object Array

Transceiver regards a communication process as a source of Source to the target, such a process is a Channel in Transceiver, and this Channel is composed of at least two ports (one for Source, One for Target, so a number of channels that are unprofitable and Source, Target are freely combined, must declare an array of objects for multiple port classes for Source and Target (and establish a corresponding association relationship for them. You will see). Such as:? Private

??? {private declarations}

Tcpsource: Array of TServersocket; // A number of objects used for TCP SOURCE

TCPTARGET: Array Of TclientSocket; // A number of objects for TCP Target

??? mailsource: array of tidpop3;? // A number of objects used for Mail Source

MailTarget: Array of Tidsmtp;? // An array of objects used for Mail Target

Filesource: array of tfileport; ?? // A number of objects used for File Source

??? filetarget: array of tfileport; ?? // An array of objects used for File Target

??? comsource: array of tcomport; // A number of objects used for COM SOURCE

COMTARGET: Array of Tcomport; // An array of objects used for COM Target

Note: Due to the same type of port running rules for Source and Target, it is considered completely different and there is no direct relationship in the Transceiver concept. So the same type of Port, the object array is also established by Source and Target.

?????????????????????????? IV. ?????????????

Each number of elements of each object is managed by Port Builder. If the user defines some type of Port through Transceiver Console, Port Builder will instantiate the object array according to the number and each parameter. Otherwise, the object array will not be instantiated. In the Source Type Port Object, the Name property is set to the form of 'Receive' port ID, which will help Data Dispatcher positioning objects and unified scheduling for Data Dispatcher locating objects and different types of PORT objects. Tag properties are used to provide Channel Controller's Target ID information.

The following is an instantiated part of the COMSource object array in Port Builder

???? begin // Create COM /

Receive port

?????? itmp: = high (casource) 1;

/ / Get the current maximum number of COMSource, ITMP is Integer variable

SETLENGTH (COMSource, ITMP 1); // Add a COMSource array member

?????? comsource [itmp]: = tcomport.create (self); // instantiate member

COMSource [itmp] .name: =

'Receive' INTOSTR (isource);

/ / Set the name attribute to 'Receive' port id, isource is the current portid

?????? comsource [itmp] .tag: = iTarget; // Set the target ID of its Channel

?????? nulltest: = remove.fields ['address']. Value;

// Get the system configuration of the computer, Nulltest is a Variant variable

?????? if (NullTest <> null) and (Trim (NullTest) <> ') THEN

???????????? begin

COMSource [itmp] .comface: = nullte; // Take a valid value to COMFACE

Nulltest: = Rece.fields ['Interval']. Value;

/ / Get the trigger time interval of obtaining data in the system configuration

Settimer (Application.handle, ISource, NullTest * 60000, NIL);

/ / Establish a trigger clock for the current port for timing, isource is the port ID

end

Else

COMSource [itmp] .tag: = - 1; // Initialization failed, identified as invalid port

???

COMSource is a Source class port for calling and obtaining data at a certain time interval, and obtains the implementation of the data, the implementation of the COMTARGET is similar to it, but because the COMFACE submission data to the Comtricget is a real-time process, it is not necessary to use To trigger interval, omit two statements for establishing the clock. Other types of Port objects are created and initialized. For example, another mailtarget implementation segment:

????????????? begin // Create SMTP / Send Port

??????????????? ITMP: = high (mailtarget) 1;

??????????????? setLength (MailTarget, ITMP 1);

??????????????? MailTarget [ITMP]: = tidsmtp.create (Self);

??????????????? MailTarget [ITMP] .Name: = 'send' INTOSTR (Itarget);

??????????????? MailTarget [ITMP] .tag: = 3; // Set to target port type ID

??????????????? nulltest: = remove.fields ['address']. Value; // mail server address

??????????????? IF (NullTest <> NULL) AND (TRIM (NULLTEST) <> ') THEN

???????????????????????????????? MailTarget [ITMP] .host: = NullTest

Else? bvalid: = false;

??????????????? nulltest: = remove.fields ['port']. Value; // mail server port

??????????????? IF NULLTEST <> NULL? THEN

(if NullTest <> 0 Then MailTarget [ITMP] .port: = nulltest)

Else? bvalid: = false;

??????????????? nulltest: = Rece.fields ['user']. Value; // login user name

??????????????? if nulltest <> null tell, mailtarget [itmp] .Userid: = nulltest

Else? bvalid: = false;

??????????????? nulltest: = remove.fields ['password']. Value; // login password

?????????????? ?? .............

????????????????????????????????? .............

????????????? End;

Maybe you will have such a doubt, a large number of Transceiver shell communication components are created by Port Builder at runtime, is the TRANSCEIVER SERVICE performance? In fact, the Mission of Port Builder is done at once in ServiceCreate events. The number of shell port will only affect the initialization speed of Transceiver Service. The communication speed of Shell Port and the overall performance of Transceiver Services will not be affected. Of course, system resources It may take more.

???????????????????????????? v.?????, event, dynamic allocation and processing of events

Among the various communication ports supported by Transceiver Shell, use TSERVERSOCKET (probably you prefer to use Indy communication components, but this does not violate Transceiver Service's design ideas, just the modification or increase in the shell level). TCPSource is One of the more features, because TSERVERSOCKET is a Source Port, which is different from the COM or POP3, which requires timed trigger, which is in the Listening state after the Transceiver Service starts, and generates corresponding when there is a ClientSocket connection and send data Event components. The following is an instantiation segment of Tcpsource:

Begin // CREATE TCP / Receive Port

? itmp: = high (tcpsource) 1;

? SetLength (Tcpsource, ITMP 1);

? Tcpsource [itmp]: = TSERVERSOCKET.CREATE (Self);

Tcpsource [itmp] .onclientRead: = TCPSERVERSCLIENTREAD;

/ / Assign the processing of the onClientRead event to TCPserversClientRead

Tcpsource [itmp] .onclientror: = TCPSERVERCLIENTERROR;

// Allocate the processing of the OnClienTerror event to TCPServerClientError

Tcpsource [itmp] .name: =

'Receive' INTOSTR (isource);

/ / Set the name attribute to 'Receive' port ID

Tcpsource [itmp] .tag: = itarget; // Set to its Channel Target ID

Tcpsource [itmp] .socket.data: = @ tcpsource [itmp] .tag;

// attach the target ID of this Port as the pointer data to the socket object

???? ...............

???? ...............

END;

Come back and then look at our COMSource process. When instantification, we build a trigger clock for it, but how to handle the event when the clock is triggered? Similarly, it is also dynamic allocation of event processing.

COMSOURCE clock processing definitions to join:? Application.onMessage: = Timer; Realize the overload of message processing, when there is an Application message, Timer will be triggered, in the Timer event we filter Handling the WM_TIMER message triggered by the clock, you can press the PORT ID and type to implement the call to the data acquisition method of a specific Source Port:

Procedure TCARRier.Timer (var Msg: TMSG; VAR Handled: Boolean);

Var? stmp: string;

???? Obj: tcomponent;

Begin

? if msg.Message = wm_timer life // Handling Clock Message

? begin // find the object that defines this message according to the port ID of the trigger message

Obj: = Findcomponent ('Receive' INTSTR (Msg.wParam));

??? if obj = nil dam; // Did not find it to exit

??? stmp: = obj.classname; // Reflective Type Information for this Port Object

??? if stmp = 'TidPop3' Then getPOP3 (TIDPOP3 (OBJ));

??? if stmp = 'tidftp' Then Getftp (TIDFTP (OBJ));

??? if stmp = 'tfileport' Then getfile (TFILEPORT (OBJ));

If stmp = 'tcomport' Ten Getcom (Tcomport (OBJ));

// Call the data acquisition process of COMSource

???? ...............

???? ...............

? End;

END;

?????????????????????????? Vi. ????????????? acquisition data

The following is the data acquisition process of COMSource

Procedure tcarrier.getCom (COMOBJ: TCOMPORT);

Var stmp: String;

??? COMINTERFACE: Olevariant;

Begin

??? Try // established a COM component object according to the value of Comface

????? cominterface: = creteoleObject (comoBj.com);

????? stmp: = cominterface.getdata; // Call the agreed interface method, get data

????? While stmp <> # 0 do? // # 0 Extraction of the agreed data extraction

????? begin

???????? DataArrive (STMP, COMOBJ.TAG);

// Treated with Data Dispatcher, Comobj.tag is the target port ID of the object where the object is located.

???????? stmp: = cominterface.getdata;

????? end;

????? cominterface: = UNASSIGNED;

??? eXcept

????? cominterface: = UNASSIGNED;

???

End; / / Complete data extraction operation, release component object until the next trigger call

The following is the data acquisition processing of TCPSource:

Procedure tcarrier.tcpserversclientRead (Sender: Tobject; Socket: tcustomwinsocket);

Begin

DataArrive (Socket.ReceiveText, Integer (TSERVERWInsocket (sender)); // is handed over to Data Dispatcher, the second parameter is the Target Port ID pointer value attached to the Socket object Sender,

END;

Different types of Source Port objects are also different from the way they receive data, but they will ultimately handle the received data to Data Dispatcher. From the implementation level, a new Source Port is implemented for each of the data reception objects and implements its data reception. Note: This author only implements the text data, which may receive memory objects, data streams, or binary data, which can be changed slightly to the received code.

????????????????????????? vii. ????????????? data scheduling

The data scheduling of the Transceiver Service is done by the Data Dispatcher logic unit. The main task of Data Dispatcher is to manage and control the data received from different Source Port, working with the Channel Controller, press Channel's definition to different TARGET Portigns data distribution, monitors its success, and determines whether the data needs to be submitted to Queue Manager and Log Recorder to make buffer and log processing depending on the send results and system configuration libraries. Next, look at the DataArrive method submitted by Source Port:

Procedure TCARRier.DataArrive (SDATA: STRING; PORTID: Integer);

VAR DTIME: DATETIME;

??? ilogid: integer;

??? bsendseccess: boolean

Begin

? if sdata = '' Then EXIT; // If the data is empty

??????????? ilogid: = - 1;

? DTIME: = now; ?? // Receive time

• IF SDATA [Length] = # 0 THEN SDATA: = COPY (SDATA, 1, Length (SDATA) -1);

// String format for compatible with C language

Bsendseccess: = Datasend (SDATA, PortID);

// Call Data Dispatcher Send Scheduling Method, Portid is Target Port ID

IF (tscfg.logonlyError = false) or (bsendseccess = false? THEN

Ilogid: = WriteLog (DTIME, NOW, SDATA, PORTID, BSENDSECESS);

/ / Record the log processing rules and send results based on the log processing rules in the system configuration information

??? i i (tscfg.queueing = true) and (bsendseccess = false)? THEN

????????? Putqueue (DTIME, NOW, SDATA, PORTID, BSENDSEC 30, ILOGID);

?? // Determine Queue Processing according to the Queue Configuration Decision in Packaging System Configuration Information

END;

The above is the Data Dispatcher's DataArrive method, where the Queue's processing is determined according to the system configuration information and the transmission status, or can be adjusted to mandatory queue processing. Below is the Data Dispatcher's Datasend method, which is used to distribute data to Target Port type:

Function TCARRIER.DATASEND (SDATA: STRING; PORTID: Integer): Boolean;

Var obj: tComponent; Begin

? Datasend: = false;

Obj: = FindComponent ('send' INTOSTR (portid)); // Find objects according to port ID

? if (obj = nil) or (obj.tag = -1) THEN EXIT;

// Object does not exist or due to initial failure has been identified as invalid port

Case Obj.tag of

? 1: Datasend: = PUTTCP (TclientSocket (OBJ), SDATA);

? 3: Datasend: = Putsmtp (Tidsmtp (obj), SDATA);

? 5: Datasend: = Putftp (TIDFTP (OBJ), SDATA);

7: DataSend: = PuthTTTP (TIDHTTP (OBJ), SDATA);

? 9: Datasend: = Putfile (TFilePort (Obj), SDATA);

11: Datasend: = PUTMSMQ (TMSMQPort (OBJ), SDATA);

? 13: Datasend: = PUTDB (TDBPORT (OBJ), SDATA);

? 15: Datasend: = Putcom (Tcomport (Obj), SDATA);

???? ...............

???? ...............

? End;

END;

It is worth noting that if there is no object array, it is only one instance of each type of Port, the better way to handle data distribution processing should be the use of the callback function, but in the current situation, it will result in I don't know which member should be processed from the object array. In addition, the current processing method makes Transceiver Kernel and Transceiver Shells completely peeled, and should seek more abstract and independently.

??????????????????????? viii. ????????????? data transmission

The following is the transmission of TCP

Function Tcarrier.puttcp (TCPOBJ: TCLIENTSOCKET; SDATA: STRING): Boolean

Var itime: integer;

Begin

Puttcp: = false;

? Try

??? TCPOBJ.CLOSE;

??? tcpobj.open;

??? itime: = gettickcount; // start time

??? repeat

????? Application.ProcessMessages;

??? Until (tcpobj.active = true) or (getCount-itime> 5000);

???? // Jump out of the loop when the connection is successful or 5 seconds

??? if tcpobj.active kil

??? begin

????? tcpobj.socket.sendtext (sdata);

????? puttcp: = true; // When sending data is successful, the return value is TRUE

END;

TCPOBJ.CLOSE;

? EXCEPT

TCPOBJ.CLOSE;

? End;

? End;

The following is the transmission of COM

Function Tcarrier.putcom (Comobj: Tcomport; SDATA: STRING): Boolean

Var COM: olevariant;

Begin

? Putcom: = false;

? Try

??? com: = createoleObject (como.comface); // Establish a predefined interface

Putcom: = com.putdata (sdata); // Call predefined method

COM: = unassigned;

? EXCEPT

COM: = UNASSIGNED ;? END;

END;

Other types of PORT transmission is similar, and details will not be described here. So far, the basic processing of Source and Target has been completed. A basic communication function has been established, and the completely different communication functions can be achieved through free match of different types of Source and Target. Establish multiple Channel, you can focus on multiple different functional communication processing.

???????????????????????????????????????? Queue processing

Data Dispatcher will call the PUTQUE method of the data log record, the Data Dispatcher is called the PUTQUE method of the data log record, and the functionality is similar, and the data information is stored according to the system parameters, not The focus of this article. The queue's Retry processing is similar to the principle of PORT type distribution processing, which relies on Queue Timer's trigger, read buffer data from the database, and calls Datasend again according to Target Port ID Data transmission retry If the transmission is successful, the transaction of this data transmission is completed, otherwise, re-enter the queue is waiting for the next trigger time for retry until the maximum retry number of settings is successfully or reached.

Third, ??????????? Development experience summary

Due to the focus of this article, the core ideology and design concept of Transceiver, simplify and weaken Transceiver as a multi-threaded process, object pool, and transaction support should consider, more complex Source and Target GROUP management and Channel Integration, sending and receiving memory objects, data streams, binary data, system configuration information, implementation, system and data security, etc. Inspirational sparks in actual development work make more excellent software.

?

?

Author: Firebird

Redbirdli@hotmail.com

Establish communication and data exchange servers with Delphi - TRANSCEIVER technology (on)

Establish communication and data exchange servers with Delphi - TRANSCEIVER technology (below)

Take a collection class overview .NET Collectes and related technologies via C #

Old Things: Program Shortcut / Program Delete / EXE Self Delete DIY

Old things: childhood programming algorithm

?

转载请注明原文地址:https://www.9cbs.com/read-30354.html

New Post(0)