⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtcconn.pas

📁 Delphi快速开发Web Server
💻 PAS
📖 第 1 页 / 共 5 页
字号:
      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 + -