📄 rtcconn.pas
字号:
the last set timeout interval), or to a negative value (-1) to
disable the timeout on this event. }
property AfterDataSent:integer read FAfterDataSent write FAfterDataSent default 0;
end;
{ @abstract(Basic connection component wrapper)
TRtcConnection is the Basic connection component wrapper (client & server).
It publishes methods and handles all the tasks that are common to all
connection components. All connection components are indirect descendants
of TRtcConnection and therefor inherit all its methods and properties.
@longcode(#
VERY IMPORANT!!! If you create connection components at runtime:
* NEVER! use Create(), Free or Destroy on ANY connection component.
* Allways use the 'NEW' class function (implemented by all TRtcConnection
components) to create the connection object and
* ONLY use the 'RELEASE' method to free the connection object. #)
@html(<b>)
MULTITHREADED CLIENT/SERVER:
@html(</b><br><br>)
When @Link(TRtcConnection.MultiThreaded) property for this connection is True,
your events will be called from within a Thread inside a Thread pool.
If you decide to use your component(s) in a multithreaded environment,
you have to keep in mind that all Data is being sent and received in
the background, from threads belonging to the RTC Thread Pool.
This implementation is thoroughly tested and works perfectly in
any mulithreaded environment (tested on a dual-processor machine with
thousands of clients accessing the server at the same time). But,
to keep the code working for you, you will have to follow a few simple rules.
@longcode(#
1. Accessing the component in MultiThreaded mode:
A) After a connection is initiated ('Connect' was called),
your code which needs to access any methods or properties of
that component, HAS TO BE synchronized with any background threads
that might be using the component to process background requests.
The easiest way to work with any TRtcConnection component
in a multithreaded mode is to implement everything as events.
There are enough event handlers declared, so that most of
the things can be done this way.
The mechanism integrated into TRtcConnection components makes sure that
events triggered by the connection component DO NOT OVERLAP with callback
functions and messages called by Windows. This means that you can safely
use the component from ANY EVENT you define for that component.
When the event is triggered, you are the owner of the component
and nothing will access the component during your event execution.
B) But, there will probably be situations where you do not want to
wait for a connection event in order to do something with your connection.
To be able to access the connection components from anywhere else
than your event handlers (for example, from a Button click event),
even when they are running in multithreaded mode, you will use
TRtcConnection components ability to POST A JOB to itself.
All actions that TRtcConnection components do, are defined by
small jobs that have to be executed. When there are no jobs waiting
for execution, there are no Threads or CPU resources used.
Jobs are objects that contain DATA AND EXECUTION CODE. You can
create jobs by extending the TRtcJob class and implementing
your classes Run and Kill methods (defined as abstract by TRtcJob).
After creating an instance of your TRtcJob class and initializing
it with the data you need to execute the Run method, you can
post your job object to your connection component by using
the PostJob method (also implemented by TRtcConnection).
2. Accessing the GUI from events in MultiThreaded mode:
For your components events in which you need to access the GUI (Graphical
User Interface: any visual component) when working in multithreaded mode,
you SHOULD use the connection components inMainThread property to check if
your event is currently being executed from the mail thread. If the result is
TRUE, you may continue execution. If the result is False, you HAVE TO use
the connection components 'Sync' method to call your event synchronized
(that could also be the same event you are now inside). The event passed
as a parameter to Sync will be called from the Main Thread, puting the
background thread (from which you called Sync) in a waiting state,
until the event execution is over.
Here is one 'Access GUI from OnDataReceived event' example:
procedure TMyForm.ServerOnDataReceived(Sender:TRtcConnection);
begin
// first, check if you are inside the Main Thread.
if not Sender.inMainThread then
begin
// we are not in the main thread.
// to be able to access the GUI,
// we will call the event synchronized.
Sender.Sync(ServerOnDataReceived);
end
else
begin
// We are in the main Thread.
// We can safely access the GUI from here.
end;
end;
This OnDataReceived event handler example wants to have GUI access
throughout the event execution, so it checks if it is inside
the Main Thread and calls itself synchronized.
Naturaly, for events which do not need to access the GUI,
you can simply implement the event, without ever checking the
inMainThread property or using the Sync method. #) }
TRtcConnection = class(TRtcComponent)
private
FInfo:TRtcInfo;
FCS:TRtcCritSec;
FReconnecting:boolean;
FRecTimer:TRtcTimer;
FMultiThread:boolean;
FFree:boolean;
FReadyToRelease:boolean;
FActive:boolean;
FClosing:boolean;
FParent: TRtcConnection;
FTimeout: TRtcTimeout;
FPort:string;
FAddr:string;
FOverLimit:boolean;
FMyEvent:TRtcNotifyEvent;
FMyErrMsg:Exception;
FMyErrEvent:TRtcErrorEvent;
FMyUserMsg:TObject;
FMyUserEvent:TRtcUserEvent;
FMyFunc:TRtcFunctionInfo;
FMyFuncResult:TRtcValue;
FMyFuncEvent:TRtcFunctionCallEvent;
FMyFuncData:TRtcValue;
FMyResultEvent:TRtcResultEvent;
FInsideSync:boolean;
FInsideEvent:integer;
FConnectOp:boolean;
FConnecting:boolean;
FListening:boolean;
FDisconnecting:boolean;
FStopping:boolean;
FReleasing:boolean;
FConnectTriggered:boolean;
FConnectingTriggered:boolean;
FOnConnect:TRtcNotifyEvent;
FOnConnecting:TRtcNotifyEvent;
FOnDisconnect:TRtcNotifyEvent;
FOnDisconnecting:TRtcNotifyEvent;
FOnException:TRtcErrorEvent;
FOnDataOut:TRtcNotifyEvent;
FOnDataIn:TRtcNotifyEvent;
FOnDataSent:TRtcNotifyEvent;
FOnDataReceived:TRtcNotifyEvent;
FOnReadyToSend:TRtcNotifyEvent;
function GetParent:TRtcConnection;
{ Check Parent connection. All connections connected to a local listener
have this listener as their Parent. }
property Parent:TRtcConnection read GetParent;
function GetState: TRtcConnectionState;
function GetVersionSDK:string;
procedure SetVersionSDK(const s:string);
protected
{ @exclude }
FDataOut:cardinal;
{ @exclude }
FDataIn:cardinal;
{ @exclude }
FReadCount:int64;
{ @exclude }
FWriteCount:int64;
{ Connection provider component,
set by TRtcConnection after calling the CreateProvider method.
@exclude }
Con:TRtcConnectionProvider;
// @exclude
procedure SetMultiThread(const Value: boolean); virtual; abstract;
{ Create a new connection provider and return it as a result.
@exclude }
function CreateProvider:TObject; virtual; abstract;
{ Release the connection provider
@exclude }
procedure ReleaseProvider; virtual;
{ @name is called by TRtcConnection before Connect or Listen,
to copy parameters from the Connection component to
the Connection Provider component. This is the method in which
the connection component should initialize the connection provider's
parameters with the ones set for the connection component.
@exclude }
procedure SetParams; virtual;
{ @name is called by TRtcConnection before Connect or Listen,
to set connection provider's triggers to connection component's
events, so that connection provider and connection component
can work together as a team.
@exclude }
procedure SetTriggers; virtual;
{ @name is called by TRtcConnection after a connection was closed,
to clear all connection provider's triggers, so that he connection
provider doesn't cause an access violation in case the connection
component is being released after disconnect, while the connection
provider is still receiving old events or finalizing the connection.
@exclude }
procedure ClearTriggers; virtual;
{ @name is used internally to implement the synchronization
mechanism used by the Sync(Event) method.
@exclude }
procedure CallMyEvent;
{ @name is used internally to implement the synchronization
mechanism used by the Sync(Event,Err) method.
@exclude }
procedure CallMyError;
{ @name is used internally to implement the synchronization
mechanism used by the Sync(Event,Obj) method.
@exclude }
procedure CallMyUserEvent;
{ @name is used internally to implement the synchronization
mechanism used by the Sync(Event,Par,Res) method.
@exclude }
procedure CallMyFuncEvent;
{ @name is used internally to implement the synchronization
mechanism used by the Sync(Event,Res) method.
@exclude }
procedure CallMyResultEvent;
{ AfterDestroy event,
ready to be mapped to a connection provider's trigger.
@exclude }
procedure TriggerAfterDestroy; virtual;
{ BeforeCreate event,
ready to be mapped to a connection provider's trigger.
@exclude }
procedure TriggerBeforeCreate; virtual;
{ ReadyToRelease event,
needs to be implemented by connection component,
so it can be mapped to a connection provider's trigger.
@exclude}
procedure TriggerReadyToRelease; virtual; abstract;
{ Connecting event,
ready to be mapped to a connection provider's trigger.
@exclude }
procedure TriggerConnecting; virtual;
// @exclude
procedure CallConnecting; virtual;
{ Connect event,
ready to be mapped to a connection provider's trigger.
@exclude }
procedure TriggerConnect; virtual;
// @exclude
procedure CallConnect; virtual;
{ Disconnecting event,
ready to be mapped to a connection provider's trigger.
@exclude }
procedure TriggerDisconnecting; virtual;
// @exclude
procedure CallDisconnecting; virtual;
{ Disconnect event,
ready to be mapped to a connection provider's trigger.
@exclude }
procedure TriggerDisconnect; virtual;
// @exclude
procedure CallDisconnect; virtual;
{ DataOut event,
ready to be mapped to a connection provider's trigger.
@exclude }
procedure TriggerDataOut; virtual;
// @exclude
procedure CallDataOut; virtual;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -