0% found this document useful (0 votes)
182 views

RTC SDK Tutorial 1

The document summarizes the RealThinClient SDK, which allows developers to write stable clients, servers, and ISAPI extensions in Delphi. It provides concise, event-driven communication that can handle thousands of connections using limited system resources. Key features include easy deployment as standalone servers or ISAPI extensions, a plug-in framework, remote functions, encryption, compression, and a small footprint. The SDK package includes server components like RtcHttpServer to implement HTTP and compile components into a standalone server.

Uploaded by

Roket Software
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
182 views

RTC SDK Tutorial 1

The document summarizes the RealThinClient SDK, which allows developers to write stable clients, servers, and ISAPI extensions in Delphi. It provides concise, event-driven communication that can handle thousands of connections using limited system resources. Key features include easy deployment as standalone servers or ISAPI extensions, a plug-in framework, remote functions, encryption, compression, and a small footprint. The SDK package includes server components like RtcHttpServer to implement HTTP and compile components into a standalone server.

Uploaded by

Roket Software
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

RealThinClient SDK V1.

9n

DeltaSoft

RealThinClient SDK
Quick-Start Guide

RealThinClient SDK
Write stable Clients, Servers and ISAPI extensions in Delphi 4 - 2006

Server:

Client:
RealThinClient SDK V1.9n

Why should I use the RealThinClient SDK?


No more problems with Firewalls or Proxy servers (runs over HTTP)
Write Internet-ready Clients (see demos)
Write Internet-ready Servers (see demos)
Write ISAPI Extensions (100% Apache 2.x and MS IIS 5.x ready)
Write Template-based Applications (separate visual and business layers)
One code compiles as Stand-alone Server and/or ISAPI Extension
Debug ISAPI extensions using the RTC WebServer (full source code included)
Call/Write Remote Functions (extremely fast, easy to use and flexible)
Powerful Multi-Threading (automatic, enabled by setting a property)
Compression and strong Encryption (automatic, activate with a property)
Modular Design (pack your code in data modules and use it as plug-ins)
Rapid Development (write your application code, not interfaces)
Includes full source code, ready to be used with:
- Borland Delphi 4, 5, 6, 7, 2005 and 2006 (Win32)
- Borland C++ Builder 4, 5 and 6
- Lazarus/Free Pascal (Windows)

Can you tell me more?


All RTC components are stress-tested for the highest stability.
Check Test Results for more info.

By using non-blocking event-driven communication with a built-in thread-pooling


mechanism, RealThinClient SDK can handle thousands of active connections by using
a limited number of threads in a real multi-threaded environment (for example, 100
threads will be more than enough to handle several thousand active connections).
Combined with reduced need for all important resources (CPU, Memory, Threads,
Timers, Handles, etc), automatic handling of all communication-related objects, flexible
remote functions (accept any structure for parameters and return any other structure as
a result), automatic session handling (integrated time-out with variable life time) and a
lot more, makes writing stable and performance Servers and Clients very easy with
RealThinClient components.

2
RealThinClient SDK V1.9n

RealThinClient SDK : Short Feature list


Easy Deployment: Write one server app and compile it as a robust Stand-alone
ISAPI Extensions and Server executable, capable of serving unlimited number of
Stand-alone Servers clients, or as an ISAPI DLL Extension, which can be
deployed with any ISAPI-capable Web Server (for example:
MS IIS or Apache).

RAD: Everything you do with RTC is component-based, while all


Write events, the code you will ever need to write is defined as events, so
not interfaces you can design your server and client applications, without
the need to use wizards or write interfaces.

Easy Multithreading: A very sophisticated Threading mechanism is built into all


turn on/off with RTC Connection components, which allows thousands of
a simple switch active connections to be running in separate threads, all at
the same time. And the only thing you need to do is change
a simple Multithreaded property to True. Then, any newly
received connection will be handled by a thread pooling
mechanism which saves valuable System resources, while
still enabling nearly unlimited number of simultaneous
connections at the same time.

HTTP protocol: RTC Clients will never have to be specially configured to get
No Firewall problems through corporate firewalls and reach the internet. Simply by
setting the UseProxy property to True, Data Client
connection will use a connection provider which uses the
same settings to read and send its data to the internet, as
MS Internet Explorer does for browsing the Web. This
means that Clients can work in any corporate LAN and have
full access to the internet.

Non-Blocking Other than most other internet components, RTC connection


components are non-blocking and event-driven. This means
that, even when not using a multithreaded mode, your users
will not be blocked ("Application Not Responding") during
communication between your client and the server. For each
state change in the connection, there is an event that will be
triggered.

3
RealThinClient SDK V1.9n

Remote Functions: Implementing and using remote functions is as easy as


reusable, writing local functions. You just place one RtcFunction
easy to write, component on your Form or a DataModule, set function
easy to call name and write your OnExecute event. OnExecute event
receives the Connection object, Function Parameters and a
Result object. You just have to use the parameters passed
to the function to prepare the result. The rest is done "under
the hood" by RealThinClient components.

Strong encryption & RTC components offer built-in, easy-to-use strong


automatic compression encryption with Encryption Keys of variable length and
automatic data compression. You don't even have to think
about encryption keys or data compression, everything will
be generated and maintained for you. Using strong
encryption and compression with remote functions is
completely transparent, you will never have to worry about
encryption or compression again. Simply set Encryption and
Compression parameters in RtcClientModule and
RtcServerModule, the rest is up to RTC.

Plug-In Framework: All Client and Server code you write using RTC SDK is
write your own plug-ins ready to be used as building blocks or plug-ins in any
or use 3rd-party plug-ins application that uses RTC SDK. For example, you can
combine a Web Server, Messenger server, Application
server, Database server and your own functions in one Data
Server, even when those components weren't specially
designed to share the same Server space. Because of the
easy-to-use plug-in framework on top of which all RTC
Components are built, you can link unlimited number of
functionality and data providing components like
RtcDataProvider, RtcServerModule and/or
RtcDataServerLink to one Data Server connection
component, enhancing that server's functionality with each
new component. And by keeping code in separate units
(Data Modules), you can even provide your own plug-ins
(and sell those plug-ins) to anyone who uses the RTC SDK
Library.

Small Footprint A complete Web Server implementation, using RTC SDK, is


less than 600 KBytes when compiled with D7. Even though
it is so small, it offers enough functionality with great stability
and scalability.

4
RealThinClient SDK V1.9n

What is inside the RealThinClient SDK package?


RealThinClient SDK : Server components

RtcHttpServer: implements the HTTP protocol over TCP/IP and is used to compile
RTC components into a stand-alone server application (extends TRtcDataServer).
All high-level server-side RTC components use TRtcDataServer descendants to
communicate with HTTP Clients (RTC Clients, Web Browsers, SOAP Clients, etc).
Best practice is to write all your code using high-level server-side RTC components
separated on different data modules, then use one extra DataModule where you will
use one RtcHttpSever to compile the functionality into a stand-alone server
application (EXE).

RtcISAPIServer: implements the ISAPI interface and is used for writing extensions
for ISAPI-compatible web servers (extends TRtcDataServer). All high-level server-
side RTC components use TRtcDataServer descendants to communicate with
HTTP Clients (RTC Clients, Web Browsers, SOAP Clients, etc). Best practice is to
write all your code using high-level server-side RTC components separated on
different data modules, then use one extra DataModule where you will use one
RtcISAPISever to compile the functionality into one ISAPI extension (DLL).

RtcDataProvider: used to implement events which will handle HTTP requests and
prepare responses (for example, client requests a file, which has to be read from a
local drive and written out as a response). Each Data Provider only responds to his
requests, ignoring the rest. This makes Data Providers work as plug-ins for the
Server, which can be used alone or in combination with other RTC components to
create a powerful and multifunctional Server.

Here is a short list of possible Data Providers:


- File provider to send files
- PHP provider to process php scripts and send HTML pages out
- SOAP provider to implement different Web Services
- Page providers to generate dynamic HTML pages
- Image providers to dynamically generate images for the Web
- anything else, there is no limit

RtcFunction: link one RtcFunction to one RtcFunctionGroup, make sure that


Function Group is assigned to one RtcServerModule, choose a "FunctionName" and
write your function code in the OnExecute event. That's all you have to do to add a
new remote function to your RTC Server.
When writing a remote function, you don't have to think about anything but your
function code. In case of an exception (which you can also raise inside your
OnExecute event handler), client will get the exception message as a result
(Result.isType=rtc_Exception), so you don't even have to worry about that.

5
RealThinClient SDK V1.9n

RtcFunctionGroup: provides access to a group of functions. When used by a


RtcServerModule, it automatically enables access to remote functions for all RTC
Clients. When used by a RtcClientModule, it gives server the ability to call client-side
functions as a result of client's function calls.

To implement remote functions, you will need at least one RtcFunctionGroup


component and link one or more RtcFunction components to it. Function Groups
also enable you to call other functions from the same group to fill parameters for
other function calls. RtcFunctionGroup is primarily used by the RtcServerModule
and RtcClientModule components to hold implementations for their remote
functions, but it can also be used directly by any other component.

RtcServerModule: execution point for a group of Remote Functions. It enables the


Server to provide remote access to its remote functions. RtcServerModule has no
events which would have to be implemented, you just link a RtcServerModule with
its Server on one side and a RtcFunctionGroup on the other side to enable remote
functions.

RtcDataServerLink: very useful when you have a number of Data Provider or Server
Module components spread across units, because it groups related Data Provider
components and links them to their Data Server connection. If you only have one or
any small number of Data Provider components, you can link them directly to Data
Server connection component, without the need of a RtcDataServerLink.

6
RealThinClient SDK V1.9n

RealThinClient SDK : Client components

RtcHttpClient: used by all Client-side RTC components to communicate with HTTP


Servers (RTC Servers, Web Servers, Web Service providers, etc).

Unless you decide to implement your own communication protocol by using low-
level connection components, this is the component that will be responsible for
direct communication with your servers: it sends requests prepared by higher-level
client-side RTC components like RtcDataRequest and RtcClientModule, then
accepts responses and uses the same higher-level components to process those
responses. Check Data Request components (Client side) for more info.

RtcDataRequest: client-side counterpart to RtcDataProvider. It enables the client to


post requests to a RTC Server or any other HTTP Server. Using this component,
you can request files from a Web Server, post a SOAP request to a Web Service,
execute a server-side PHP script, etc. Everything any HTTP Server is providing, you
can request it using this component.

RtcClientModule: client-side counterpart to RtcServerModule. It enables the client to


call functions provided by the Server through one of its Server Modules.
RtcClientModule has no events which would have to be implemented, you just link a
RtcClientModule to a Client connection component (RtcHttpClient) and you can call
remote functions.

If you define client-side functions and link them to this RtcClientModule, this will be
the execution point of those client-side remote functions. No special implementation
needed. Client-side remote functions are functions which server can call on the
client-side as a result of client's calls to a server-side function.

RtcResult: process results received from remote function call(s). Using the
"OnResult" event, which receives the connection (Sender:TRtcConnection),
parameters sent (Param:TRtcValue) and the result received (Result:TRtcValue), you
can easily write the code to process the result. Maybe only do a simple check if
function executed successfully, or show a message dialog, or create a separate
form containing all data received, or fill received content into other component on the
same form or datamodule (for example, fill ClientDataSet with records from a
database).

RtcDataClientLink: very useful when you have a number of Data Request or Client
Module components spread across units, because it groups related client request
components and links them to their Data Client connection. If you only have one or
two data request components, you can link them directly to Data Client connection
component, without the need of a RtcDataClientLink.

7
RealThinClient SDK V1.9n

RealThinClient SDK : Data types used with Sessions and Remote Functions
RTC SDK supports all native and complex data types for working with Sessions and Remote
Functions. You can use any data type to store and access data in a session and/or to send
and receive data between clients and servers using RTC remote functions.

method: isType Returns type of data stored in a specific variable, used mostly in
check if and what kind of data has client sent as parameters to a
remote function call and to check if and what kind of data has
server sent back to the client as a result from a remote function
call.

type: rtc_Null Returns True if parameter is not set (it is "NULL"). You can set
access: isNull "isNull" to True to clear the variable/parameter.

type: rtc_Boolean
Boolean value (Delphi type: boolean)
access: asBoolean

type: rtc_Integer
Integer value (Delphi type: longint)
access: asInteger

type: rtc_LargeInt
Large Integer value (Delphi type: int64)
access: asLargeInt

type: rtc_Float
Float value (Delphi type: double)
access: asFloat

type: rtc_Currency
Currency value (Delphi type: currency)
access: asCurrency

type: rty_DateTime Date and Time value. Always use this type to work with Dates
access: asDateTime and Times (Delphi type: TDateTime)

type: rtc_String
String value (Delphi type: AnsiString, up to 2GB in size)
access: asString

type: rtc_Text Text value, automatically coded and encoded using UTF-8
access: asText (Delphi type: AnsiString)

type: rtc_WideString
Wide String value (Delphi type: WideString, up to 2GB in size)
access: asWideString

type: rtc_Variable
Use to send/receive variable names (Delphi type: AnsiString)
access: asVariable

type: rtc_Exception Use to send/receive exception message (string). If exception is


access: asException raised from the OnExecute event (and not handled by that event),
client will receive the exception message "asException".

8
RealThinClient SDK V1.9n

type: rtc_ByteStream Use to work with Streams. When you use "newByteStream", an
create: newByteStream in-memory stream will be created, which you can access using
access: asByteStream "asByteStream". When used with remote functions, data stored in
a stream will be sent/received between client/server as any other
data type.

type: rtc_Record Use to work with records. In records, each element is accessed
create: newRecord using a name (string). Each element in a record can be of any
access: asRecord type (even an array, record, dataset or function call).

type: rtc_Array Use to work with arrays. In arrays, each element is accessed
create: newArray using an index of type integer. Each element in an array can be of
access: asArray any type (even an array, record, dataset or function call).

type: rtc_DataSet Use to work with datasets. In datasets, you browse/insert/delete


create: newDataSet records as you would usually do with Delphi's TDataSet (using
access: asDataSet prior/next/insert/append/delete), while you have access to fields
from a current record using names (same as in a record). Each
field in a dataset can be of any type (even an array, record,
dataset or function call).

type: rtc_Function Use "newFunction" to prepare a remote function call, setting


create: newFunction function name and all parameters. Each parameter can be of any
access: Param type supported by TRtcValue. This means that one parameter of
TRtcFunctionInfo can hold virtually anything, from a simple value
to a complex data structure or another remote function call (even
a complete set of function calls).

RealThinClient SDK : Low-Level connection components


RtcTCPServer: low-level TCP/IP Server connection component for
communication using streamed TCP/IP data, which you can extend to
implement your own TCP/IP-based protocols. There is no special built-in
formatting enforced by the component.

RtcTCPClient: low-level TCP/IP Client connection component for communication


using streamed TCP/IP data, which you can extend to implement your own
TCP/IP-based protocols. There is no special built-in formatting enforced by the
component.

RtcUDPServer: low-level UDP Server connection component for communication


using raw UDP data packages, which you can extend to implement your own
UDP-based protocols. There is no special built-in formatting enforced by the
component.

RtcUDPClient: low-level UDP Client connection component for communication


using raw UDP data packages, which you can extend to implement your own
UDP-based protocols. There is no special built-in formatting enforced by the
component.

9
RealThinClient SDK V1.9n

Introduction
If you want to use RealThinClient SDK components, the best place to start is this
QuickStart guide. After going through the online lessons, you should also go through
the QuickStart examples included in the RTC SDK package (QuickStart folder). You can
download the Open Source RTC SDK package before you get a commercial license.

Once you finish examining the QuickStart examples, I suggest browsing through the
FAQ and Support section. Even if you won't be reading all the articles, you should at
least get the feeling about the information included there. Another good source of
information are RTC SDK Demos, which are included in the RTC SDK package and
have a lot of examples and best practices for using the RealThinClient SDK.

And, last but not least, the most extensive source of information on the RealThinClient
SDK are Help files. Some of the information is spread across the files, but if you know
which class you need, you will most likely be able to find what you are looking for.

When you start working on your project, the FAQ will come in handy when you have to
do something specific (use Sessions, accept form post data, write and call remote
functions, etc). The FAQ is continually being extended, as more questions come in.

If you have a question for which you were unable to find the answer in the QuickStart
g u id e , Q u ickS ta rt e xa m p le s, th e F A Q o r th e S u p p o rt se ctio n … a n d se a rch in g th ro u g h
the Help files didn't give you the answers you need, don't hesitate to post your question
to the Developer Support section.

Licensed RTC SDK Bronze, Silver and Gold users can also send their question(s)
directly to me by E-Mail at [email protected]. Please include your Share*it order
number when asking questions by E-Mail.

10
RealThinClient SDK V1.9n

Prepare: Install RTC SDK


Before you can install the RTC SDK, you have to download it. If you have ordered a
commercial license, please log into the Forum and get the latest commercial package.
Those who want to try the RTC SDK out or use it for non-commercial purposes, can
download the RTC SDK Open Source (GPL) package for free from the Orders page.
To install the RTC SDK, you have to:

1 Start Delphi and open the appropriate rtcSDK_XY.dpk (Delphi Package) file,
located in the Lib folder.
2 Compile and install the package.
3 From Delphi menu, under Environment Options, select the "Library" tab and
add the full path to the "Lib" folder to "Library path".
4 You can then open any Demo project (from Demos folder) and compile it. If it
doesn't compile because of "missing files", you need to check and correct the
Library path in Environment Options and try again.

How to use this Quick-Start Guide?


This is a guide to help you with your first steps with the RealThinClient SDK. It is divided
into lessons. Each lesson will show you (step-by-step) how to use RTC components to
accomplish a specific task. Every new lesson builds on one of the previous lessons. It is
best to start from the bottom (Server Lesson 1) and work your way up. If you have any
questions or suggestions regarding any of the lessons, feel free to post them to the
Support section on this forum.

11
RealThinClient SDK V1.9n

Server Lesson 1: Write your first RTC Server

1 Start a new Project in Delphi

2 from the RTC Server tab, put RtcHttpServer on your form:


set ServerPort = 80

3 or your Form, define OnCreate event:


RtcHttpServer1.Listen;

4 from the RTC Server tab, put RtcDataProvider on your form:


set Server = RtcHttpServer1

4b for RtcDataProvider1, define OnCheckRequest event:

with Sender as TRtcDataServer do


if UpperCase(Request.FileName)='/TIME' then
Accept ;

4c for RtcDataProvider1, define OnDataReceived event:

with Sender as TRtcDataServer do


if Request.Complete then
Write('Current time is: '+TimeToStr(Now));

5 Compile and Run the project.

When you run the project, your Server will immediately start to Listen on Port 80 (if you
used the Port number from this lesson).

NOTE: In case your Server doesn't start normally and you end-up with "Error 10048 in
function bind: Address already in use." exception, it means that you have another Web
Server running on Port 80 already.

Since only one application can listen on a specific port, you either have to change the
ServerPort in this example (maybe use Port 81) and compile the project again, or stop
the other WebServer before running this example, so you can use Port 80.

12
RealThinClient SDK V1.9n

6 Using a web browser, go to http://localhost/time

NOTE: If you have changed the Port number to something different from 80 (standard
HTTP port), you will also have to use this port number in your browser. For example, if
you used Port 81, your URL should look like this:

http://localhost:81/time

You should get a response like "Current time is: 23:15:38".

Server Lesson 2: Send dynamically generated content

This lesson continues where Server Lesson 1 stops. You will see in this lesson how two
data providers work together and how you can use multiple "Write" calls to send
complex content out. You can scroll down for the complete source code and textual
version of this lesson.
or small files or files where you feel can fit safely in your server's memory (for example,
up to 32K) or to prepare web site output, there's no need to split the transfer. You can
write the file out directly from the OnDataReceived event of your RtcDataProvider
component. You can also use the Write method consecutively.

Let's add a new RtcDataProvider component to our server app, which will produce a site
with a list of all square values from 1 to 100.

1 Open the Project created in Lesson 1.


2a from the "RTC Server" tab, put a new RtcDataProvider on the form:
set Server = RtcHttpServer1

2b define the OnCheckRequest event:

// we want to access this request with "/square"


with TRtcDataServer(Sender) do
if UpperCase(Request.FileName)='/SQUARE' then
Accept;

13
RealThinClient SDK V1.9n

2c define the OnDataReceived event:


var
line:integer;
begin
with TRtcDataServer(Sender) do
if Request.Complete then
begin
Write('<html><body>');
Write('Here comes a table of square values ... <br>');
for line:=1 to 100 do
begin
// I will use 3 write calls here,
// you can use one (makes no difference).
Write('Square of '+IntToStr(line)+' = ');
Write(IntToStr(line*line));
Write('<br>');
end;
Write('......... done.');
Write('</body></html>');
end;
end;

3 Compile and Run the project.


4 Start your Browser and go to http://localhost/square

If everything went ok, you should see a list of square values. You can also see that the
other data provider is till working by going to http://localhost/time
The same way, you can send binary data out. The only thing you need to do is read the
data into a string from the file. I will show you how to do this, in the next lesson.

Server Lesson 3: Sending small files from a folder


Let's say we want to write a simple Web Server, which will provide access to small files
in a specific folder.
1 Open the Project created in Lesson 1 or Lesson 2 (either one will do).

14
RealThinClient SDK V1.9n

2 from "RTC Server" tab, put a new RtcDataProvider on your form:


set Server = RtcHttpServer1
set CheckOrder = 900

NOTE: We want to send a file out ONLY if other data providers didn't accept the request.
To achieve this, we have defined our place in the check order using the CheckOrder
property. Our assumption here is that that all other RtcDataProvider components have a
lower CheckOrder.

3 copy this function into your main form's unit:

{ We need a function to convert our Request.FileName to a local file name.


All files are in a sub-folder "/data", placed in the same folder as our server. }

function GetFullFileName(fname:string):string;
var
DocRoot:string;
begin
// Get the executable file's folder name ...
DocRoot:=ExtractFilePath(ExpandFileName(ParamStr(0)));
// Make sure the file doesn't end with '\' ...
if Copy(DocRoot,length(DocRoot),1)='\' then
Delete(DocRoot,length(DocRoot),1);
// We want to use a sub-folder named '\data' ...
DocRoot:=DocRoot+'\data';
// Requests use "/" instead of "\" ...
fname:=StringReplace(fname,'/','\',[rfreplaceall]);
// Create file name containing full path
Result:=ExpandFileName(DocRoot+fname);
{ Check if the file is inside our folder
(don't want people to use "..\" to move out of this folder) }
if UpperCase(Copy(Result,1,length(DocRoot)))<>
UpperCase(DocRoot) then
Result:=''; // return empty file name.
end;

15
RealThinClient SDK V1.9n

4 for RtcDataProvider3, define the OnCheckRequest event:


{ This time, we will accept any Request for which we can find
a file in our folder, specified in "Request.FileName" }
var
fname:string;
begin
with TRtcDataServer(Sender) do
begin
fname:=GetFullFileName(Request.FileName);
if (fname<>'') and (File_Exists(fname)) then
begin
Accept;
{ We will store the file name in our request,
so we don't have to recreate it again later. }
Request.Info['fname']:=fname;
end;
end;
end;

5 for RtcDataProvider3, define the OnDataReceived event:

{ We assume that the files will be short and we will be sending them
out in one run. In that case, we can simply send the whole file
out from our OnDataReceived event. }
var
fname:string;
begin
with TRtcDataServer(Sender) do
if Request.Complete then
begin
fname:=Request.Info['fname'];
if File_Exists(fname) then
Write(Read_File(fname))
else
{ 'Write' will ensure that
response is sent, even if empty. }
Write;
end;
end;

16
RealThinClient SDK V1.9n

6 Compile and Run the Project.


This lesson got a bit complicated, because I wanted to use a folder relative to our exe
file and there has to be some file handling so clients don't get access to our whole drive.
To test how the server works, use Windows Explorer to create a sub-folder named 'data'
inside the folder where your project's executable file is created, then put a file named
'test.txt' there.
Once you have the folder with a file and the server is running, open your Internet
Browser and download the file, using this link: http://localhost/test.txt
If everything went ok, you should get the file in your Browser window. If you place other
files in the 'data' folder, you can download them by using their name.
It makes no difference whether the file is a text file, image or an executable file.

I assumed that the file is small enough to be read in one call and sent out directly,
without splitting the thing in multiple events. With larger files, there is a small
modification we will have to do. I will come to this in the next lesson.

Server Lesson 4: Sending large files out


To be able to send large files out, without using up all our server's memory to hold the
file, we can split the sending procedure in several event calls. There is a small difference
between the 2 methods:

A) Sending all out at once


When you want to send all out at once, which is the easiest and the best way to do if you
are preparing web sites or other dynamically generated content, you will only need the
implement the OnCheckRequest and OnDataReceived events and use the Write method
from OnDataReceived event to write the whole content out. This is what we did in the
last few examples.

B) Sending a large response in several turns


To be able to send large content out (like large files), additionally to the events we used
on out RtcDataProvider components, we will need the OnDataSent event. This event will
be called after all data prepared with prior calls to Write have been sent out to the client
and all sending buffers are empty. Other than that, we will need some insight into our
TRtcDataServer's Response property.

17
RealThinClient SDK V1.9n

Let's go and change the example from Lesson 3 a bit, so we can also send large files
with it. We will define a memory limit of 16K for a single event call, to keep our memory
usage as low as 16K for any client requesting a file from our server.

1 We will change the OnCheckRequest event for our last RtcDataProvider component, to
set the Response.ContentLength value to the file size. To do this, double-click on the
last RtcDataProvider component to jump to the OnCheckRequest event provider.

There is only a small addition to the event, but to keep it all in one place, here's the
complete new event implementation:

var
fname:string;
begin
with TRtcDataServer(Sender) do
begin
fname:=GetFullFileName(Request.FileName);
if (fname<>'') and (File_Exists(fname)) then
begin
Accept;

// We will store the file name in our request,


// so we don't have to recreate it again later.
Request.Info['fname']:=fname;
{ We need to set the Response.ContentLength,
to tell the RtcDataServer how large the content
(data) in our response will be.
If we do not set the Response.ContentLength,
RtcDataServer will assume that the first event which
calls Write has prepared the complete response and
will calculate the ContentLength for us. }
Response.ContentLength:=File_Size(fname);
{ We will send the Response Header out,
so we don't have to call Write
in case our File size is zero. }
WriteHeader;
end;
end;
end;

18
RealThinClient SDK V1.9n

2 Then, we will update the OnDataReceived event of our RtcDataProvider, to send only
limited amount of data out (let's set that limit to 16KB). And here is the updated
OnDataReceived event handler:
var
fname:string;
len:cardinal;
begin
with TRtcDataServer(Sender) do
if Request.Complete then
begin
// Check if we have to send more data.
if Response.ContentLength>Response.ContentOut then
begin
fname:=Request.Info['fname'];
// Only continue if the file hasn't changed in size.
if File_Size(fname)=Response.ContentLength then
begin
// calculate how much we still need to send.
len:=Response.ContentLength - Response.ContentOut;
// Limit the length to send at once to 16KB
if len>16000 then len:=16000;
// Send 'len' bytes from our file,
// starting at position "Response.ContentOut"
Write( Read_File(fname, Response.ContentOut, len) );
end
else
{ Disconnect the client, because our file
has changed and we have sent
the wrong header and file beginning out. }
Disconnect;
end;
end;
end;

3 We will use the same event handler method we defined for OnDataReceived for our
OnDataSent event. To do this, from the Object Inspector's Window, we can simply copy
the event name for the OnDataReceived event to the OnDataSent event.

Warning: do not remove the OnDataReceived event. Both events (OnDataReceived and
OnDataSent) should use the same implementation. That's all there is to it.

19
RealThinClient SDK V1.9n

What will happen exactly? First, the "OnCheckRequest" event will be called, which will
check if a file with requested name exists, then accept the request and set the
"Response.ContentLength" property (our file size) and write the response header out
(by calling "WriteHeader").
Then, "OnDataReceived" event will be called, but we won't react to it until we receive
the complete request body (Request.Complete).
After we get the complete request, we will send up to 16K of our file out. If the file is
larger than 16K, "OnDataSent" event will be called every time our data has been sent
out and it is safe to continue sending the next package.
On each call to our "OnDataSent" event, we will send up to 16K bytes of data out, until
our "Response.ContentOut=Response.ContentLength".

To test how this works, you can place a large file into the "/data" sub-folder, open your
favorite Internet browser and request the file. You will not see the difference at the client
side between the old and the new implementation, but the new implementation will only
use up to 16K of memory, while the old one will put the whole file into memory before
sending.

Additional RTC Server components information


There are a few things that could be useful when sending out web content.

One of them is access to the request parameters using the Request:TRtcServerRequest


property and also access to all header values for the response using the
Response:TRtcServerResponse property of your connection component
(Sender:TRtcDataServer).

If you had the pleasure of writing dynamic HTML content using PHP, Java or some
other language, you already know something about HTTP headers

Task Command
Request method (GET, PUT, HEADER, etc) Request.Method
File name requested Request.FileName
Query variables coming after filename (the Request.Query[ variable_name ]
thing coming after '?' in the Http request)
Host (domain) name requested (the thing Request.Host, or Request['Host']
coming after "http://" and before the file name)
Type of the content received Request.ContentType, or
Request['Content-type']

20
RealThinClient SDK V1.9n

Task Command
Total Length of the Content client is sending: Request.ContentLength, or
Request['Content-length']
Read data received as contant body Read
Content bytes received in the request so far: Request.ContentIn

For more info on the TRtcDataServer.Request property, check the Help for these
classes:
-TRtcServerRequest
-TRtcRequest
- TRtcHttpHeader

And here a few examples for using the Response property


(set before first call to Write or WriteHeader)

Task Command
Type of the content you want to send out. Response.ContentType, or
Response['Content-type']
Length of the content you want to send out. Response.ContentLength, or
Response['Content-length']

If length was not set manually, it will be calculated automatically depending on the length
of the content that was written in the first event.

Task Command
Status code you want to send, Default = 200 Response.StatusCode
Status text you want to send, Default = OK Response.StatusText

For more info on the TRtcDataServer.Response property, check the Help for:
- TRtcServerResponse
- TRtcResponse
- TRtcHttpHeader

For more info on the TRtcHttpServer component, check the Help for these classes:
- TRtcHttpServer
- TRtcDataServer
- TRtcServer
- TRtcConnection

For more info on the TRtcISAPIServer component, check the Help for these classes:
- TRtcISAPIServer
- TRtcDataServer
- TRtcServer
- TRtcConnection

21
RealThinClient SDK V1.9n

For more info on the TRtcDataProvider component, check the Help for these classes:
- TRtcDataProvider
- TRtcAbsDataServerLink

A lso , th e re is a n o th e r co m p o n e n t, w h ich w a sn ’t m entioned in the lessons, but will be of


great interest to you if you are using more than one RtcDataProvider component and
want to have the code split on multiple data modules (maybe to separate application
parts). It's the RtcDataServerLink component.

Each RtcDataProvider component can be linked to a RtcDataServer connection


component in two ways.

1.) Directly by setting the Server property or


2.) By linking to the server through a RtcDataServerLink component.

I find that all things that can be done using the Object Inspector at design-time, should
be done using the Object Inspector at design-time, because it is much easier to do. And
for that, RtcDataServerLink is there to make it easier for you to connect a group of
RtcDataProvider or RtcServerModule components to your RtcDataServer connection
component (for example, RtcHttpServer).

Since there will be only one RtcDataServer component for the whole server app, but you
will most likely have a number of data modules with a number of RtcDataProvider and
RtcServerModule components on them, which all have to be linked to that one
RtcDataServer (and you can not do this at design-time if RtcDataServer is on a different
form or module), you can place a RtcDataServerLink component on every data module
(or form) where your components with server's functionality (RtcDataProvider,
RtcServerModule, RtcFunctionGroup, RtcFunction, etc) are and link those components
to that RtcDataServerLink. Then, at runtime, before you call RtcHttpServer.Listen (or
from the OnCreate event of your ISAPI Extension's main DataModule), you can set the
Server property for your RtcDataServerLink components, and don't have to do this in for
each RtcDataProvider or RtcServerModule component.

22
RealThinClient SDK V1.9n

Client Lesson 1: Request a File from any HTTP Server


This is the first client lesson. You will learn in this lesson how to use rtcHttpClient and
rtcHttpRequest components to get data from the server. You can find the complete
source code and textual version of this lesson below.
Here is an example how you can write a client which will receive any file it requests from
a server.
1 Start a new Project in Delphi

2 Put one Edit field on your form (name "Edit1")


set Text = /

3 put one Memo field on your form (name "Memo1")


set ScrollBars = ssBoth

4 from the "RTC Client" tab, put one RtcHttpClient on your main form:
set MultiThreaded = True
set ReconnectOn.ConnectLost = True
set ServerAddr = www.realthinclient.net
set ServerPort = 80
set UseProxy = True

5a from the "RTC Client" tab, put one RtcDataRequest on your form:
set Client = RtcHttpClient1
set AutoRepost = 2
set AutoSyncEvents = True

5b for RtcDataRequest1, define the "OnBeginRequest" event:

with TRtcDataClient(Sender) do
begin
// make sure our request starts with "/"
if Copy(Request.FileName,1,1)<>'/' then
Request.FileName:='/'+Request.FileName;
// define the "HOST" header
if Request.Host='' then
Request.Host:=ServerAddr;
Memo1.Text:='Requesting "'+Request.FileName+
'" from "'+ServerAddr+'".';
// send request header out
WriteHeader;
end;

23
RealThinClient SDK V1.9n

5c for RtcDataRequest1, define the "OnDataReceived" event:

with TRtcDataClient(Sender) do
begin
if Response.Started then
begin
{ Executed only once per request,
when we start receiving the response. }
// Clear the info we wrote here in our "OnBeginRequest"
Memo1.Clear;
Memo1.Lines.Add('Status code: '+
IntToStr(Response.StatusCode));
Memo1.Lines.Add('Status text:'+
Response.StatusText);
Memo1.Lines.Add('ALL Headers:');
Memo1.Lines.Add(Response.HeaderText);
Memo1.Lines.Add('Content Length:');
Memo1.Lines.Add(IntToStr(Response.ContentLength));
Memo1.Lines.Add('Content body:');
Memo1.Lines.Add('START >');
end;
{ Could be executed more than once, depending on the content size }
// add content received now.
Memo1.Text:=Memo1.Text+Read;
if Response.Done then
begin
{ Executed only once per request,
when we have just received it all. }
Memo1.Lines.Add('< END');
end;
end;

6 for your Form, define the OnCreate event:

// We will connect our client to the server on start


RtcHttpClient1.Connect;
// and get the index file from the server
with RtcDataRequest1 do
begin
Request.Method:='GET';
Request.FileName:='/'; // index file
Post; // Post the request
end;

24
RealThinClient SDK V1.9n

7 for Edit1, define the "OnKeyPress" event:

if Key=#13 then
with RtcDataRequest1 do
begin
Request.Method:='GET';
// request the file defined in the Edit field
Request.FileName:=Edit1.Text;
Edit1.SelectAll;
Post; // Post the request
end;

8 Connect to the internet, then Compile and Run the project.

If everything went ok, after you start the project, you should see the HTML code of the
index file from the www.realthinclient.net server and be able to use the Edit field to enter
any file name and get its content inside the memo field after pressing the Enter key.

In this example, content is received piece-by-piece and filled into the Memo field by
adding the text Read to Memo's text and special care had to be taken to avoid clearing
the memo in the middle of receiving. If you want to receive all content at once, you can
change the "OnDataReceived" event for your RtcDataRequest1 to this:

with TRtcDataClient(Sender) do

if Response.Done then

begin
{ This will be called only once for every request.
That will be when we receive the complete response. }
// Clear the info we wrote in our "OnBeginRequest"
Memo1.Clear;
Memo1.Lines.Add('Status code: '+ IntToStr(Response.StatusCode));
Memo1.Lines.Add('Status text:'+ Response.StatusText);
Memo1.Lines.Add('ALL Headers:');
Memo1.Lines.Add(Response.HeaderText);
Memo1.Lines.Add('"CONTENT-LENGTH" Header:');
Memo1.Lines.Add(Response['CONTENT-LENGTH']);
Memo1.Lines.Add('Content Length as integer:');
Memo1.Lines.Add(IntToStr(Response.ContentLength));
Memo1.Lines.Add('Content body:');
// add all content received
Memo1.Lines.Add( Read );
end;

25
RealThinClient SDK V1.9n

You can access response header information in different ways:

(1) all headers as text using "Response.HeaderText";


(2) each header variable separately by using "Response['variable-name']";
(3) most header information specially prepared for easier access
("Response.ContentLength", "Response.Query", "Response.Cookie",etc).
The same rules apply to request info (Request.HeaderText, Request['variable'],
Request.ContentLength, etc).

Even though "Response.ContentLength" could be undefined (zero) if Server only


supports HTTP/1.0 (server will end the response with a disconnect), you can always use
the "Response.ContentIn" property to check how much of the response content has
already arrived. This will increment for each package received, even if you do not call
"Read".

Other interesting events when receiving data are the "OnResponseDone" and
"OnConnectLost" events. "OnResponseDone" event will be triggered after the last
"OnDataReceived" event (after all data has been received), while the "OnConnectLost"
event gets called in case your connection drops after executing the OnBeginRequest
event, but before you received the complete response in the OnDataReceived event.

To store received data in a stream, you can open the stream from the "OnDataReceived"
event when "Response.Started", append (to the stream) everything you "Read" from the
"OnDataReceived" event and close the stream from "OnResponseDone" and
"OnConnectLost" events.

26
RealThinClient SDK V1.9n

Server Lesson 5: Write your first RTC remote function


This is the first server lesson for writing remote functions. You will learn in this lesson
how to use rtcServerModule, rtcFunctionGroup and rtcFunction components to write
functions which can be called remotely by RTC clients. You can find the complete
source code and textual version of this lesson below.

1 Open a new Project


2 from the RTC Server tab, put RtcHttpServer on your form:
for RtcHttpServer1, set ServerPort = 80
3 for your Form, define OnCreate event:
RtcHttpServer1.Listen;

You will notice that this is the same thing we did for sending files and dynamic content
out. If you want to have a server that does multiple things, not only process remote
function calls, you can also start from point (5) on any of other Server lessons, to add
remote function capabilities.

4 from the RTC Server tab, put one RtcFunctionGroup on your form:
You will use one FunctionGroup for each Form or Module where you want to
implement remote functions.

5 from the RTC Server tab, put one RtcServerModule on your form:
set Server = RtcHttpServer1
set FunctionGroup = RtcFunctionGroup1
set ModuleFileName = '/mytest'

ModuleFileName is case-sensitive, so remember exactly what you use here,


you will have to use exactly the same ModuleFileName in your rtcClientModule
component for the Client. You will use one rtcFunction component for each
function you want to implement.

6a from the RTC Server tab, put one RtcFunction on your form:
set FunctionGroup = RtcFunctionGroup1
set FunctionName = 'hello'

27
RealThinClient SDK V1.9n

6b for RtcFunction1, define the OnExecute event:


Result.asString := 'Hello, '+Param.asString['name'];

7 Compile and run the project.

C o n tin u e w ith C lie n t L e sso n 2 …

Client Lesson 2: Call your first RTC remote function


This is the first client lesson for calling remote functions. You will learn in this lesson how
to use rtcClientModule and rtcResult components to call remote functions served by a
RTC server. This lesson continues where Server Lesson 5 stops. You can find the
complete source code and textual version of this lesson below. Here is an example how
you can write a client to call remote functions from a server.

1 Start a new Project in Delphi

2 Put one Edit field on your form (name "Edit1")


se t T e xt = ‘U se r’

3 put one Memo field on your form (name "Memo1")


set ScrollBars = ssBoth

4 from the "RTC Client" tab, put one RtcHttpClient on your main form:
set AutoConnect = True
set MultiThreaded = True
set ReconnectOn.ConnectLost = True
set ServerAddr = localhost
set ServerPort = 80
set UseProxy = True

5a from the "RTC Client" tab, put one RtcClientModule on your form:
set Client = RtcHttpClient1
set AutoRepost = 2
set AutoSyncEvents = True
set ModuleFileName = '/mytest'

5b from the "RTC Client" tab, put one RtcResult on your form

28
RealThinClient SDK V1.9n

5c for RtcResult1, define the "OnReturn" event:


Memo1.Lines.Add( Result.asString );

6 for Edit1, define the "OnKeyPress" event:


if Key=#13 then
begin
Edit1.SelectAll;
with RtcClientModule1 do
begin
// Prepare a new remote function call
with Data.newFunction('hello') do
begin
// set function call parameters
asString['name']:=Edit1.Text;
end;
// Call the remote function
Call(RtcResult1);
end;
end;

7 Start the Server (from Server Lesson 5), then Compile and Run this client
project.

If everything went ok, after you start both projects, when you enter some text in
the Edit field and press the Enter key, you will receive a response in your Memo
component.

In this example, we are passing a single string parameter ('name') and receive a
single string as a result. You can pass any kind of data to the server as
parameters and receive any structure as the result. Please check the FAQ for
more info.

29
RealThinClient SDK V1.9n

Server Lesson 6: Write an ISAPI Extension using RTC


This is the first server lesson for writing ISAPI extensions. You will learn in this lesson
how to create a new ISAPI Extension project and use RTC SDK components to write
code which can be compiled as a stand-alone Server and as ISAPI Extension. This
lesson has a lot of information, which makes it essential for anyone interested in writing
ISAPI Extensions. You can find the complete source code and a short textual version of
this lesson below.
The only difference between ISAPI extensions and stand-alone applications is the
project type and connection component you have to use. While for Stand-alone servers
you will create a normal Windows application and use the rtcHttpServer connection
component, for ISAPI extensions you will create an ISAPI Extension project (dll) and use
the rtcISAPIServer connection component.
Here are 4 simple steps to create a new ISAPI Extension project ...

1 From the "Lib" folder (in RTC), open the "rtcISAPIProject.dpr" project. You will
use this project as a template for creating ISAPI Extensions.

2 Save this project in a folder of your choice, under a name of your choice.
Use the "Save Project as ..." option from the File menu to save this as your new
ISAPI extension project. After you have saved this project in a folder of your
choice, to complete your ISAPI extension creation, you will need one
DataModule with one rtcISAPIServer component on it.

3 Add one DataMoudule to your new ISAPI Project.

4 from the RTC Server tab, put RtcISAPIServer on your new DataModule.

Now you have your first ISAPI extension ready, but it needs something to do.

You do not have to call Listen, nor set any properties for the RtcISAPIServer
component, since everything will be handled by your WebServer (RTC will
simply process requests).

For demonstration purposes, we will add the same "/Time" DataProvider to this
main DataModule (the same thing we did in the first Server Lesson).

30
RealThinClient SDK V1.9n

5 from the RTC Server tab, put RtcDataProvider on your DataModule:


for RtcDataProvider1, set Server = RtcISAPIServer1

6 .for RtcDataProvider1, define OnCheckRequest event:


with Sender as TRtcDataServer do
if UpperCase(Request.FileName)='/TIME' then
Accept;

7 for RtcDataProvider1, define OnDataReceived event:


with Sender as TRtcDataServer do
if Request.Complete then
Write('Current time is: '+TimeToStr(Now));

8 Compile the project.

If everything went ok, there should be a new DLL in your Project's folder, ready to be
installed in your WebServer. After you install this DLL in your WebServer and start the
WebServer, you should be able to access this extension as any other ISAPI Extension
and use the "/TIME" request to get current Server's time.

To be able to write server-side code which can be compiled as a stand-alone server and
as ISAPI extension, you will place all your components on DataModules instead of
Forms and link them to one rtcDataServerLink (using the "Link" property of each
component) instead of linking them directly to a Server connection component.

All RTC SDK components will work the same, no matter if they are connected to a
RtcHttpServer or a RtcISAPIServer component. As long as you write your server-side
code in DataModules, you can create two projects: (1) one as a standard Windows
application which will use a RtcHttpServer component and (2) another as ISAPI
Extension project which will use a RtcISAPIServer component.

By linking your components from DataModules to the connect component your project
needs, you have one code which works as a stand-alone server and as ISAPI Extension.
Please check the "File_Server" and "App_Server" demos for more info.

31
RealThinClient SDK V1.9n

Where to go from here?


Now you have the basic understanding of RealThinClient SDK components. As you start
using the components to implement more complex tasks, you will need to extend your
knowledge about the RealThinClient SDK components.

The best place to start looking for answers is on the RTC Forums, which are located
here: http://www.realthinclient.com/forum

In ca se yo u n e e d h e lp u sin g th e R T C S D K co m p o n e n ts, d o n ’t h e sita te to a sk q u e stio n s


on the RTC Forums or RTC Newsgroups.

32

You might also like