-
-
Save Coldzer0/226e0d4ac724e0c511895b4485594e28 to your computer and use it in GitHub Desktop.
mORMot2 Async Client Demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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