Skip to content

Instantly share code, notes, and snippets.

@Coldzer0
Last active October 26, 2021 10:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Coldzer0/226e0d4ac724e0c511895b4485594e28 to your computer and use it in GitHub Desktop.
Save Coldzer0/226e0d4ac724e0c511895b4485594e28 to your computer and use it in GitHub Desktop.
mORMot2 Async Client Demo
Program AsyncClient;
Uses
mormot.core.fpcx64mm,
{$IfDef windows}
windows,
{$Else}
cthreads,
BaseUnix,
{$EndIf}
SysUtils,
StrUtils,
mormot.net.async,
mormot.net.sock,
mormot.net.client,
mormot.core.os,
mormot.core.base,
mormot.core.buffers,
mormot.core.rtti,
mormot.core.threads,
mormot.core.Text,
mormot.core.log;
Type
{ TNewConnection }
TNewConnection = Class(TAsyncConnection)
Protected
Function OnLastOperationIdle(nowsec: TAsyncConnectionSec): Boolean; Override;
Function OnRead: TPollAsyncSocketOnReadWrite; Override;
Procedure OnClose; Override;
Procedure AfterCreate; Override;
Procedure BeforeDestroy; Override;
End;
{ TFastClient - Should we Use TAsyncClient?! }
TFastClient = Class(TAsyncConnections)
Private
LogFamily: TSynLogFamily;
Procedure Connect();
Protected
Function ConnectionCreate(aSocket: TNetSocket; Const aRemoteIp: RawUtf8; out aConnection: TAsyncConnection): Boolean; Override;
Public
Constructor Create(Const aRemoteHost, aTCPPort: RawUtf8); Reintroduce;
/// shutdown and finalize
Destructor Destroy; Override;
End;
Var
AsyncThreads: TFastClient;
Function TNewConnection.OnLastOperationIdle(nowsec: TAsyncConnectionSec): Boolean;
Begin
Owner.WriteString(self, 'HI_Server');
Owner.log.Add.log(sllWarning, 'LastOperationIdle % - Sending HeartBeat', [Handle], self);
Result := False;
End;
Function TNewConnection.OnRead: TPollAsyncSocketOnReadWrite;
Begin
Result := soContinue;
Owner.log.Add.log(sllServer, 'OnRead % Received Data Len [%]', [Handle, fRd.Len], self);
fRd.Reset;
End;
Procedure TNewConnection.OnClose;
Begin
Owner.log.Add.log(sllWarning, 'OnClose %', [Handle], self);
End;
Procedure TNewConnection.AfterCreate;
Begin
fLockMax := True;
Inherited AfterCreate;
End;
Procedure TNewConnection.BeforeDestroy;
Begin
Inherited BeforeDestroy;
End;
{ TFastClient }
Function TFastClient.ConnectionCreate(aSocket: TNetSocket; Const aRemoteIp: RawUtf8;
out aConnection: TAsyncConnection): Boolean;
Var
mylog: ISynLog;
Begin
If Terminated Then
Exit(False);
aConnection := nil;
mylog := fLog.Enter('Create Async Connection(%)', [PtrUInt(aSocket)], self);
aConnection := TNewConnection.Create(self, aRemoteIp);
If Not Inherited ConnectionAdd(aSocket, aConnection) Then
Begin
FreeAndNilSafe(aConnection);
mylog.log(sllWarning, 'inherited %.ConnectionAdd(%) failed', [PtrUInt(aSocket)], self);
exit(False);
End;
// assign the new connection to the internal reading poll.
If Clients.Start(aconnection) Then
Begin
// release atpReadPoll lock to handle new subscription ASAP
ThreadPollingWakeup(fClients.PollRead.PollForPendingEvents(0));
// Send 2MB As Test - we should receive it
WriteString(aConnection, DupeString('A', 1024*1024*2));
Result := True;
End
Else
Begin
mylog.log(sllWarning, 'Start: MakeAsync(%) failed add to reading poll', [pointer(aSocket)], self);
End;
End;
Constructor TFastClient.Create(Const aRemoteHost, aTCPPort: RawUtf8);
Begin
LogFamily := TSynLog.Family;
LogFamily.Level := LOG_VERBOSE;
LogFamily.PerThreadLog := ptIdentifiedInOnFile;
LogFamily.EchoToConsole := LOG_VERBOSE;
Self.LastOperationIdleSeconds := 13;
fThreadClients.Count := 0;
fThreadClients.Timeout := 10 * 1000;
fThreadClients.Address := aRemoteHost;
fThreadClients.Port := aTCPPort;
inherited Create(nil, nil, TNewConnection, 'FastClient', LogFamily.SynLogClass, [acoVerboseLog], 2);
End;
Destructor TFastClient.Destroy;
Begin
Inherited Destroy;
End;
Procedure TFastClient.Connect();
Var
res: TNetResult;
client: TNetSocket;
connection: TAsyncConnection;
Connected: Boolean;
Begin
Connected := False;
While (Not Terminated) And (Not Connected) Do
Begin
fThreadClients.Timeout := 5000;
With fThreadClients Do
res := NewSocket(Address, Port, nlTcp, {bind=}False, timeout, timeout, timeout, {retry=}0, client);
If res = nrOK Then
Begin
connection := nil;
If Not ConnectionCreate(client, {ip=}fThreadClients.Address, connection) Then
client.ShutdownAndClose({rdwr=}False)
Else
Begin
If connection <> nil Then
Begin
Connected := True;
While Not connection.IsClosed Do
SleepHiRes(1);
Log.Add.log(sllWarning, '%: connection closed - %', [self, connection], self);
Connected := False;
End;
End;
End
Else
Begin
Log.Add.log(sllWarning, '%: %:% connection failure (%)',
[self, fThreadClients.Address, fThreadClients.Port, ToText(res)^], self);
End;
End;
End;
Begin
Try
AsyncThreads := TFastClient.Create('192.168.1.8', '8080');
AsyncThreads.Connect(); // Connect or Keep trying
writeln('Something went wrong Press [Enter] to close the client.');
Readln;
Finally
FreeAndNilSafe(AsyncThreads);
End;
End.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment