📄 dxservercore.pas
字号:
// Due to the design of our ancestor servercore, this property
// allows you to control the low-level socket communications to
// either UDP/IP or TCP/IP. This allows you to design either
// solution from a single design instance unlike all of our
// competitors.
// ============================================================
property ProtocolToBind: TWhichProtocol read fWhichprotocol
write fWhichprotocol;
// =============================================================
// This property provides a mechanism that allows you to specify
// a specific IP for this instance of TDXSock to accept
// connections on.
//
// Note
// The default is blank, which allows the server to listen to
// all IP addresses found to the current NIC.
// =============================================================
property BindTo: string read fsBindTo
write fsBindTo;
// ============================================================
// All servers listen on a port for incomming connection
// requests. By default our ancestor servercore sets this to
// zero, so you do not make a mistake in your final application
// build you must set this to a non-zero port number. If you
// leave this value at zero, the operating system will
// dynamically use the next available port number over 1024 for
// the current instance of the listener. This number is
// dynamically picked between 1024 and 65536 on most windows
// \operating systems if you forget to set the serverport to a
// non-zero value.
// ============================================================
property ServerPort: Integer read fiServerPort
write fiServerPort;
// ==========================================================
// This property provides you with a mechanism to verify that
// the listener thread is running.
// ==========================================================
property IsActive: Boolean read fbActive;
// =========================================================================================
// This property <LINK TDXServerCore.Pause, pauses> and <LINK TDXServerCore.Resume, resumes>
// the listener thread.
// =========================================================================================
property Suspend: Boolean read fbSuspend
write SetSuspend;
property UseSSL: Boolean read fbSSL
write fbSSL;
// ========================================================
// This routine provides a mechanism for toggling the Nagel
// algorithm on or off for the socket layer.
//
// Note
// By default it is enabled in the DXSock suite.
// ========================================================
property UseNagle: Boolean read fbNagle
write fbNagle;
// ============================================================
// If this property is true, the listener thread will create a
// threadpool of ThreadCacheSize suspended client threads. If
// this property is false then ThreadCacheSize is the number of
// maximum conncurrent client sessions.
// ============================================================
property UseThreadPool: TDXThreePointBoolean{Boolean} read fbBufferCreates
write fbBufferCreates;
// =============================================================
// Internally all output routines use a chunking technique, this
// property allows you to specify how much data per output call
// to send to the actual socket layer buffer.
//
//
// <CODE>
// bsfRealSmall=128
// bsfSmall=256
// bsfNormal=512
// bsfBigger2048
// bsfBiggest=4096
// else use the gloabl constant TDXHugeSize
// </CODE>
// =============================================================
property SocketOutputBufferSize: TDXBlockSizeFlags read fBlockSizeFlags
write fBlockSizeFlags;
// ===========================================================
// This is the number of pending client connections that the
// socket layer will hold waiting for the listener thread to
// accept. In Windows 2000 SP3 and older operating systems the
// value range is zero to 10. Later windows operating systems
// and Linux this value can be as large as 100.
//
//
//
// When a client application sends a connect (SYN_CONNECT)
// packet, the socket layer has a queue for pending connection
// requests that the listener thread has not actually accepted
// yet. Unless your application is poorly designed this number
// can be set to 10 (the socket layer default) without ever
// losing an inbound connection.
// ===========================================================
property SocketQueueSize: Integer read fiListenerQueueSize
write fiListenerQueueSize;
// =============================================================
// TDXSock supports both blocking and non-blocking socket
// communications. This property was introduced to help
// developers moving from the Borland sockets to our suite.
//
// Note
// In testing we have found the blocking sockets can transfer
// more data in less time but having a negative affect on the
// GUI VCL thread. So if you are developing a GUI based
// application, we have found that non-blocking sockets are more
// VCL thread friendly. Also for servers like HTTP, GOPHER and
// TIME non-blocking sockets are actually faster to accept,
// receive, send, and disconnect than doing the same process
// with blocking sockets.
// =============================================================
property ServerType: TServerType read fServerType
write fServerType;
property Service: string read fDummy
write fDummy;
// ============================================================
// This property is actually the maximum number of concurrent
// connections that your application wishes to handle. We used
// the term ThreadCacheSize to avoid implying "ThreadPoolSize".
// This is only the threadpoolsize when UseThreadPool is true,
// \otherwise this is just the number of maximum concurrent
// connections.
// ============================================================
property ThreadCacheSize: Integer read GetThreadCacheSize
write SetThreadCacheSize;
property Timeout: Cardinal read fiTimeout
write fiTimeout;
// ===========================================================================================================
// After the listener thread accepts a new connection, based
// upon the threading model you have selected the listener
// assigns the new instance of TDXSock for the current client
// session to the TDXClientThread and fires this event with the
// client thread as the parameter for the communication requests
// and responses to the new client.
//
//
//
// This allows you to develop your host application more like a
// single-threaded application, as this event is the starting
// point for the actual server processes for the client.
// Descendants to TDXServerCore implement our dynamic command
// set processor which uses the client thread as a parameter to
// start negotiations of requests and replies through events.<B>
//
//
//
// If you are building your own protocol your loop would look
// something like this:</B>
// <CODE>
// While ClientThread.Socket.<LINK TDXSock.Connected, connected> do begin
// if ClientThread.Socket.<LINK TDXSock.Readable, readable> then begin
// if ClientThread.Socket.<LINK TDXSock.CharactersToRead, CharactersToRead>=0 then Exit; // disconnected
// {.. do your read here ..}
// end
// else begin
// DXString.DoSleepEx(1);
// DXString.ProcessWindowsMessageQueue;
// end;
// End;
// </CODE>
// <B>
//
// If you are using one of our existing protocol implementation
// your code would look like this:</B>
// <CODE>
// DX\<protocolname\>ServerCore.ProcessSession(ClientThread);
// </CODE>
//
// See Also
// TDXSock, OnMaxConnects, OnWakeUp, OnGoingIdle, OnAsleep
// ===========================================================================================================
property OnNewConnect: TDX_NewConnect read feNewConnect
write feNewConnect;
// =============================================================
// This event is only implemented if your host is accepting
// UDP/IP datagrams in place of TCP/IP, and you do not want to
// leverage the OnNewConnect design.
//
// Note
// This event is more low-level and provides you with a
// single-threaded listener design. So all data received from
// this event should be queued for a background thread to handle
// as the listener thread can not accept new connections while
// this event is processing. This is why we provide access to
// the SocketQueueSize for your server to allow the socket layer
// to compensate for any delays this event may introduce.
// =============================================================
property OnUDPDataNoPool: TDX_UDPData read feUDPData
write feUDPData;
// =============================================================
// Based upon the ThreadCacheSize event, if your listener has a
// pending inbound connection request but currently has too many
// concurrent connections running this event will fire. Allowing
// you to implement logic to temporarially increase the number
// \of concurrent connections, or to accept the connection and
// respond with a message that the server is currently too busy
// \- or redirect to another server if your are implementing
// load-balancing techniques in your application.
// =============================================================
property OnMaxConnects: TDX_MaxConnects read feMaxConnects
write feMaxConnects;
// =============================================================================================
// When the listener thread has not received a new client
// connection request for a small period of time, this event
// fires to inform your host application that the listener
// thread is not doing anything so it is about to go into a <LINK TDXServerCore.OnAsleep, sleep>
// mode. This event is provided as a notification only.
// =============================================================================================
property OnGoingIdle: TDX_Idle read feIdle
write feIdle;
// =============================================================
// If the listener thread has not received any client connection
// requests for a long time, and the OnGoingIdle event has
// already fired, this event fires to inform your application
// that the listener is not going to poll for new client
// connections every 10 milliseconds but slower at every 100
// milliseconds. The benefit to this design is our servercore
// produces lower CPU burden when there have not been any new
// client connections for a while.
// =============================================================
property OnAsleep: TDX_Sleep read feSleep
write feSleep;
// ===========================================================
// The listener thread will fire this event only after it has
// fired OnAsleep and a new client connection request has been
// detected.
// ===========================================================
property OnWakeUp: TDX_WakeUp read feWakeUp
write feWakeUp;
// ============================================================
// If you .<LINK TDXServerCore.Start, Start> the listener but
// for one reason or another the listener can not start, this
// event fires to provide a mechanism to interrogate the reason
// and either handle it or notify the operator of the problem.
// ============================================================
property OnListenerFailed: TDX_ListenerFailed read feListenerFailed
write feListenerFailed;
// =========================================================
// If the listener successfully started this event fires for
// notification purposes.
// =========================================================
property OnListenerStarted: TNotifyEvent read fListenerStarted
write fListenerStarted;
// =======================================================
// If the listener successfully stops this event fires for
// notification purposes.
// =======================================================
property OnListenerStopped: TNotifyEvent read fListenerStopped
write fListenerStopped;
// =============================================================
// When a new connection is accepted by the listener thread this
// event can be implemented to do a deny or accept before the
// connection information is handed to a client thread.
//
// Note
// The listener thread can not accept new connections while this
// event is processing, so your implementation of this event
// must return as fast as possible so your server does not miss
// inbound connection requests. This is why we provide access to
// the SocketQueueSize for your server to allow the socket layer
// to compensate for any delays this event may introduce.
// =============================================================
property OnAccept: TDX_OnAccept read feAccept write feAccept;
end;
implementation
uses
SysUtils,
DXSocket;
{$WARNINGS OFF}
constructor TDXClientThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
FreeOnTerminate := True;
Client := nil;
fpSessionData := nil;
end;
constructor TDXClientThreadObject.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
Client := nil;
fpSessionData := nil;
end;
{$WARNINGS ON}
{$WARNINGS OFF}
destructor TDXClientThread.Destroy;
begin
try
if Assigned(ListenerThreadObject) then
if Assigned(TDXServerCoreThread(ListenerThreadObject).fSessionTracker) then
TDXServerCoreThread(ListenerThreadObject).fSessionTracker.UnregisterSession(Self);
except
on E: Exception do begin
ShowMessageWindow('TDXClientThread.Exception#1',E.Message);
end;
end;
try
if Assigned(fpSessionData) then
if assigned(feDestroySessionData) then begin
feDestroySessionData(Self, fpSessionData);
end;
except
on E: Exception do begin
ShowMessageWindow('TDXClientThread.Exception#2',E.Message);
end;
end;
try
if Assigned(Client) then begin
Client.Free;
Client := nil;
end;
except
on E: Exception do begin
ShowMessageWindow('TDXClientThread.Exception#3',E.Message);
end;
end;
inherited Destroy;
end;
destructor TDXClientThreadObject.Destroy;
begin
try
if Assigned(ListenerThreadObject) then
if Assigned(TDXServerCoreThread(ListenerThreadObject).fSessionTracker) then
TDXServerCoreThread(ListenerThreadObject).fSessionTracker.UnregisterSession(TDXClientThread(Self));
except
on E: Exception do begin
ShowMessageWindow('TDXClientThreadObject.Exception#1',E.Message);
end;
end;
try
if Assigned(fpSessionData) then
if assigned(feDestroySessionData) then begin
feDestroySessionData(TDXClientThread(Self), fpSessionData);
end;
except
on E: Exception do begin
ShowMessageWindow('TDXClientThreadObject.Exception#2',E.Message);
end;
end;
try
if Assigned(Client) then begin
Client.Free;
Client := nil;
end;
except
on E: Exception do begin
ShowMessageWindow('TDXClientThreadObject.Exception#3',E.Message);
end;
end;
inherited Destroy;
end;
{$WARNINGS ON}
function TDXClientThread.GetSessionID: Integer;
begin
Result := ThreadID;
end;
function TDXClientThreadObject.GetSessionID: Integer;
begin
Result := GetCurrentThreadID;
end;
///////////////////////////////////////////////////////////////////////////////
//EXECUTE:
// Once this thread has "Resume"d, execute is called by TThread. This will
// fire the OnExecute (where the server protocol processes the connection)
// and once that is finished it fires the OnDisconnet event.
///////////////////////////////////////////////////////////////////////////////
procedure TDXClientThread.Execute;
begin
try
while not Terminated do begin
if Assigned(Client) then begin
Client.OutputBufferSize := fBlockSizeFlags;
if Client.ValidSocket then begin
try
TDXServerCoreThread(ListenerThreadObject).fSessionTracker.RegisterSession(Self);
if Assigned(feNewConnect) then begin
feNewConnect(Self);
end;
finally
TDXServerCoreThread(ListenerThreadObject).fSessionTracker.UnRegisterSession(Self);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -