Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
unit uMySocketTest;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, MySockets, Vcl.StdCtrls;
type
TfrmMain = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
FServer: TMyServer;
FClient: TMyClient;
public
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
procedure TfrmMain.Button1Click(Sender: TObject);
var
DT: TDateTime;
begin
FServer.PortA:= 2999;
FServer.PortB:= 2777;
FServer.Active:= True;
FClient.Port:= 2999;
FClient.Host:= '192.168.4.100';
FClient.Active:= True;
DT:= FClient.GetDateTime;
ShowMessage(FormatDateTime('mm/dd/yy hh:nn am/pm', DT));
FClient.Active:= False;
FServer.Active:= False;
end;
procedure TfrmMain.FormCreate(Sender: TObject);
begin
FServer:= TMyServer.Create(nil);
FClient:= TMyClient.Create(nil);
end;
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
FClient.Disconnect;
FServer.Active:= False;
FClient.Free;
FServer.Free;
end;
end.
unit MySockets;
interface
uses
Winapi.Windows, Winapi.Winsock, System.Classes, System.SysUtils,
IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPConnection,
IdTCPServer, IdTCPClient, IdYarn, IdContext, IdSocketHandle;
type
TMyServer = class;
TMyClient = class;
TMyServerContext = class;
TMyServerClient = class;
TMyServerClients = class;
TMyServerContext = class(TIdServerContext)
private
FID: Integer;
public
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn;
AList: TThreadList = nil); reintroduce;
destructor Destroy; override;
property ID: Integer read FID;
end;
TMyServerClient = class(TObject)
private
FOwner: TMyServerClients;
FContextB: TMyServerContext;
FContextA: TMyServerContext;
FID: Integer;
procedure SetContextA(const Value: TMyServerContext);
procedure SetContextB(const Value: TMyServerContext);
public
constructor Create(AOwner: TMyServerClients);
destructor Destroy; override;
property ContextA: TMyServerContext read FContextA write SetContextA;
property ContextB: TMyServerContext read FContextB write SetContextB;
property ID: Integer read FID;
end;
TMyServerClients = class(TObject)
private
FOwner: TMyServer;
FItems: TThreadList;
function GetItem(Index: Integer): TMyServerClient;
function GetClient(ID: Integer): TMyServerClient;
public
constructor Create(AOwner: TMyServer);
destructor Destroy; override;
function Add: TMyServerClient; overload;
function Add(ContextA: TMyServerContext): TMyServerClient; overload;
procedure Delete(const Index: Integer);
procedure DeleteID(const ID: Integer);
function IndexOfID(const ID: Integer): Integer;
function Count: Integer;
procedure Clear;
property Items[Index: Integer]: TMyServerClient read GetItem; default;
property Client[ID: Integer]: TMyServerClient read GetClient;
end;
TMyServer = class(TComponent)
private
FServer: TIdTCPServer;
FActive: Bool;
FPortB: Integer;
FPortA: Integer;
FClients: TMyServerClients;
FLastID: Integer;
procedure SvrConnect(AContext: TIdContext);
procedure SvrDisconnect(AContext: TIdContext);
procedure SvrContextCreated(AContext: TIdContext);
procedure SvrExecute(AContext: TIdContext);
procedure SetActive(const Value: Bool);
procedure SetPortA(const Value: Integer);
procedure SetPortB(const Value: Integer);
function GetLocalAddress: String;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property LocalAddress: String read GetLocalAddress;
function NewID: Integer;
published
property Active: Bool read FActive write SetActive;
property PortA: Integer read FPortA write SetPortA;
property PortB: Integer read FPortB write SetPortB;
end;
TMyClient = class(TComponent)
private
FClientA: TIdTCPClient;
FClientB: TIdTCPClient;
FPort: Integer;
FHost: String;
FActive: Bool;
FPortB: Integer;
FID: Integer;
procedure AConnected(Sender: TObject);
procedure ADisconnected(Sender: TObject);
procedure BConnected(Sender: TObject);
procedure BDisconnected(Sender: TObject);
procedure SetHost(const Value: String);
procedure SetPort(const Value: Integer);
procedure SetActive(const Value: Bool);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function GetDateTime: TDateTime;
procedure Connect;
procedure Disconnect;
property PortB: Integer read FPortB;
property ID: Integer read FID;
published
property Active: Bool read FActive write SetActive;
property Host: String read FHost write SetHost;
property Port: Integer read FPort write SetPort;
end;
implementation
{ TMyServerContext }
constructor TMyServerContext.Create(AConnection: TIdTCPConnection;
AYarn: TIdYarn; AList: TThreadList);
begin
inherited Create(AConnection, AYarn, AList);
FID:= 0;
end;
destructor TMyServerContext.Destroy;
begin
inherited;
end;
{ TMyServerClient }
constructor TMyServerClient.Create(AOwner: TMyServerClients);
begin
FContextA:= nil;
FContextB:= nil;
end;
destructor TMyServerClient.Destroy;
begin
inherited;
end;
procedure TMyServerClient.SetContextA(const Value: TMyServerContext);
begin
FContextA := Value;
FContextA.FID:= ID;
end;
procedure TMyServerClient.SetContextB(const Value: TMyServerContext);
begin
FContextB := Value;
FContextB.FID:= ID;
end;
{ TMyServerClients }
constructor TMyServerClients.Create(AOwner: TMyServer);
begin
inherited Create;
FOwner:= AOwner;
FItems:= TThreadList.Create;
end;
destructor TMyServerClients.Destroy;
begin
Clear;
FItems.Free;
inherited;
end;
function TMyServerClients.GetClient(ID: Integer): TMyServerClient;
var
L: TList;
X: Integer;
begin
Result:= nil;
L:= FItems.LockList;
try
for X := 0 to L.Count - 1 do begin
if TMyServerClient(L[X]).ID = ID then begin
Result:= TMyServerClient(L[X]);
Break;
end;
end;
finally
FItems.UnlockList;
end;
end;
function TMyServerClients.GetItem(Index: Integer): TMyServerClient;
var
L: TList;
begin
Result:= nil;
L:= FItems.LockList;
try
Result:= TMyServerClient(L[Index]);
finally
FItems.UnlockList;
end;
end;
function TMyServerClients.IndexOfID(const ID: Integer): Integer;
var
L: TList;
X: Integer;
begin
Result:= -1;
L:= FItems.LockList;
try
for X := 0 to L.Count - 1 do begin
if TMyServerClient(L[X]).ID = ID then begin
Result:= X;
Break;
end;
end;
finally
FItems.UnlockList;
end;
end;
function TMyServerClients.Add: TMyServerClient;
var
L: TList;
begin
Result:= nil;
L:= FItems.LockList;
try
Result:= TMyServerClient.Create(Self);
L.Add(Result);
Result.FID:= FOwner.NewID;
finally
FItems.UnlockList;
end;
end;
function TMyServerClients.Add(ContextA: TMyServerContext): TMyServerClient;
begin
Result:= Add;
Result.ContextA:= ContextA;
ContextA.FID:= Result.ID;
end;
procedure TMyServerClients.Delete(const Index: Integer);
var
L: TList;
begin
L:= FItems.LockList;
try
TMyServerClient(L[Index]).Free;
L.Delete(Index);
finally
FItems.UnlockList;
end;
end;
procedure TMyServerClients.DeleteID(const ID: Integer);
var
L: TList;
I: Integer;
begin
I:= IndexOfID(ID);
if I >= 0 then begin
L:= FItems.LockList;
try
TMyServerClient(L[I]).Free;
L.Delete(I);
finally
FItems.UnlockList;
end;
end else begin
//ID not found
end;
end;
procedure TMyServerClients.Clear;
var
L: TList;
begin
L:= FItems.LockList;
try
while L.Count > 0 do begin
TMyServerClient(L[0]).Free;
L.Delete(0);
end;
finally
FItems.UnlockList;
end;
end;
function TMyServerClients.Count: Integer;
var
L: TList;
begin
Result:= 0;
L:= FItems.LockList;
try
Result:= L.Count;
finally
FItems.UnlockList;
end;
end;
{ TMyServer }
constructor TMyServer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FActive:= False;
FLastID:= 0;
FClients:= TMyServerClients.Create(Self);
FServer:= TIdTCPServer.Create(nil);
FServer.ContextClass:= TMyServerContext;
FServer.OnContextCreated:= SvrContextCreated;
FServer.OnConnect:= SvrConnect;
FServer.OnDisconnect:= SvrDisconnect;
FServer.OnExecute:= SvrExecute;
FPortA:= 2701;
FPortB:= 2805;
end;
destructor TMyServer.Destroy;
begin
Active:= False;
FServer.Free;
FClients.Free;
inherited;
end;
function TMyServer.GetLocalAddress: String;
type
pu_long = ^u_long;
var
varTWSAData: TWSAData;
varPHostEnt: PHostEnt;
varTInAddr: TInAddr;
namebuf: array[0..255] of AnsiChar;
begin
If WSAStartup($101, varTWSAData) <> 0 then
Result:= ''
else begin
gethostname(namebuf,sizeof(namebuf));
varPHostEnt := gethostbyname(namebuf);
varTInAddr.S_addr := u_long(pu_long(varPHostEnt^.h_addr_list^)^);
Result:= inet_ntoa(varTInAddr);
end;
WSACleanup;
end;
function TMyServer.NewID: Integer;
begin
Inc(FLastID);
Result:= FLastID;
end;
procedure TMyServer.SetActive(const Value: Bool);
var
B: TIdSocketHandle;
IP: String;
begin
if Value then begin
if not FActive then begin
FActive:= True;
//Clear previous bindings
FServer.Bindings.Clear;
//Temporarily copy IP for lighter weight
IP:= LocalAddress;
//Create binding for port a
B:= FServer.Bindings.Add;
B.IP:= IP;
B.Port:= FPortA;
//Create binding for port b
B:= FServer.Bindings.Add;
B.IP:= IP;
B.Port:= FPortB;
//Active server
FServer.Active:= True;
end;
end else begin
if FActive then begin
FActive:= False;
FServer.Active:= False;
FClients.Clear;
end;
end;
end;
procedure TMyServer.SetPortA(const Value: Integer);
begin
if not FServer.Active then begin
FPortA := Value;
end else begin
raise Exception.Create('Cannot set port when server is active!');
end;
end;
procedure TMyServer.SetPortB(const Value: Integer);
begin
if not FServer.Active then begin
FPortB := Value;
end else begin
raise Exception.Create('Cannot set port when server is active!');
end;
end;
procedure TMyServer.SvrConnect(AContext: TIdContext);
var
C: TMyServerClient;
T: TMyServerContext;
begin
T:= TMyServerContext(AContext);
C:= FClients.Client[T.ID];
if T.Binding.Port = FPortA then begin
end else
if T.Binding.Port = FPortB then begin
end;
end;
procedure TMyServer.SvrContextCreated(AContext: TIdContext);
var
C: TMyServerClient;
T: TMyServerContext;
begin
T:= TMyServerContext(AContext);
if T.Binding.Port = FPortA then begin
C:= FClients.Add(TMyServerContext(AContext));
end else
if T.Binding.Port = FPortB then begin
//C:= FClients.Client[T.ID];
//C.ContextB:= T;
end;
end;
procedure TMyServer.SvrDisconnect(AContext: TIdContext);
var
C: TMyServerClient;
T: TMyServerContext;
begin
T:= TMyServerContext(AContext);
C:= FClients.Client[T.ID];
if T.Binding.Port = FPortA then begin
FClients.DeleteID(T.ID);
end else
if T.Binding.Port = FPortB then begin
end;
end;
procedure TMyServer.SvrExecute(AContext: TIdContext);
var
R: String;
C: TMyServerClient;
T: TMyServerContext;
I: Integer;
begin
T:= TMyServerContext(AContext);
if T.Binding.Port = FPortA then begin
C:= FClients.Client[T.ID];
T.Connection.IOHandler.ReadByte; // skip $02
R:= T.Connection.IOHandler.ReadLn(#03, 5000);
if R = 'GetID' then begin
T.Connection.IOHandler.Write(Byte($02));
T.Connection.IOHandler.Write(IntToStr(T.ID));
T.Connection.IOHandler.Write(Byte($03));
end else
if R = 'GetPortB' then begin
T.Connection.IOHandler.Write(Byte($02));
T.Connection.IOHandler.Write(IntToStr(FPortB));
T.Connection.IOHandler.Write(Byte($03));
end else begin
//Unrecognized command
end;
end else
if T.Binding.Port = FPortB then begin
T.Connection.IOHandler.ReadByte; // skip $02
R:= T.Connection.IOHandler.ReadLn(#03, 5000);
if R = 'GetDateTime' then begin
T.Connection.IOHandler.Write(Byte($02));
T.Connection.IOHandler.Write(
FormatDateTime('mm/dd/yyyy hh:nn:ss.zzz', Now));
T.Connection.IOHandler.Write(Byte($03));
end else
if Pos('SetID=', R) = 1 then begin
Delete(R, 1, 6);
I:= StrToIntDef(R, 0);
if I > 0 then begin
C:= FClients.Client[I];
C.ContextB:= T;
end else begin
//Invalid ID
end;
end else
if R = 'SomeOtherCommand' then begin
//Handle SomeOtherCommand...
end else begin
//Unrecognized command
end;
end;
end;
{ TMyClient }
constructor TMyClient.Create(AOwner: TComponent);
begin
inherited;
FID:= 0;
FClientA:= TIdTCPClient.Create(nil);
FClientA.OnConnected:= AConnected;
FClientA.OnDisconnected:= ADisconnected;
FClientB:= TIdTCPClient.Create(nil);
FClientB.OnConnected:= BConnected;
FClientB.OnDisconnected:= BDisconnected;
FHost:= 'LocalHost';
FPort:= 2701;
end;
destructor TMyClient.Destroy;
begin
inherited;
end;
procedure TMyClient.Connect;
var
R: String;
begin
FClientA.Host:= FHost;
FClientA.Port:= FPort;
FClientB.Host:= FHost;
FClientA.Connect;
//Ask server for ID
FClientA.IOHandler.Write(Byte($02));
FClientA.IOHandler.Write('GetID');
FClientA.IOHandler.Write(Byte($03));
//Read response
FClientA.IOHandler.ReadByte; // skip $02
R:= FClientA.IOHandler.ReadLn(#03, 5000);
FID:= StrToIntDef(R, 0);
//Ask server for Port B
FClientA.IOHandler.Write(Byte($02));
FClientA.IOHandler.Write('GetPortB');
FClientA.IOHandler.Write(Byte($03));
//Read response
FClientA.IOHandler.ReadByte; // skip $02
R:= FClientA.IOHandler.ReadLn(#03, 5000);
FPortB:= StrToIntDef(R, 0);
//Validate what was received
if FPortB > 0 then begin
FClientB.Port:= FPortB;
FClientB.Connect;
FClientB.IOHandler.Write(Byte($02));
FClientB.IOHandler.Write('SetID='+IntToStr(FID));
FClientB.IOHandler.Write(Byte($03));
end else begin
Disconnect;
raise Exception.Create('Unable to connect to Port B.');
end;
end;
procedure TMyClient.Disconnect;
begin
FClientB.Disconnect;
FClientA.Disconnect;
FID:= 0;
end;
function TMyClient.GetDateTime: TDateTime;
var
R: String;
begin
Result:= 0;
if FClientB.Connected then begin
//Send request for date/time
FClientB.IOHandler.Write(Byte($02));
FClientB.IOHandler.Write('GetDateTime');
FClientB.IOHandler.Write(Byte($03));
//Read response from server
FClientB.IOHandler.ReadByte; // skip $02
R:= FClientB.IOHandler.ReadLn(#03);
Result:= StrToDateTime(R);
end else begin
raise Exception.Create('Not connected!');
end;
end;
procedure TMyClient.SetActive(const Value: Bool);
begin
if Value then begin
if not FActive then begin
Connect;
end;
end else begin
if FActive then begin
Disconnect;
end;
end;
end;
procedure TMyClient.AConnected(Sender: TObject);
begin
//Main socket connected
end;
procedure TMyClient.ADisconnected(Sender: TObject);
begin
//Main socket disconnected
end;
procedure TMyClient.BConnected(Sender: TObject);
begin
//Additional socket connected
end;
procedure TMyClient.BDisconnected(Sender: TObject);
begin
//Additional socket disconnected
end;
procedure TMyClient.SetHost(const Value: String);
begin
FHost := Value;
end;
procedure TMyClient.SetPort(const Value: Integer);
begin
FPort := Value;
end;
end.