There are other properties and even events of TIdTCPServer for implementing additional behaviors related to command handlers, but the ones listed here are the ones that should be implemented as a minimum.
17.4.6 Testing the New Command
Now that an initial command has been created it can be tested easily using telnet since command handlers are text based. To test the new command:
1. Run the application.
2. From the Start : Run dialog enter: telnet 127.0.0.1 6000 and press OK. This instructs telnet to connect to the computer on port 6000 which is the port that the demo is listening on.
3. The server should reply with 200 Hello which is the greeting that was defined in the Greeting property of TIdTCPServer earlier.
4. Telnet will then display a caret. This means that the server is ready and waiting for input (i.e. a command).
5. Type HELP and press enter. The server responds with "400 Unknown Command". This is because no HELP command has been implemented yet, and the "400 Unknown Command" was what was defined in the ReplyUnknown property.
6. Type QUIT. The server responds with "200 Good Bye" and disconnects the client.
Congratulations! You have just built a server using command handlers. The next section will progress with implementing the other two command HELP and DATETIME which have different behaviors and needs from QUIT.
17.4.7 Implementing HELP
The HELP command is similar in behavior to the QUIT command with these two differences.
1. It does not disconnect.
2. In addition to the status reply, it also provides a textual response with the help information.
To implement the HELP command perform the following steps:
1. Create a new command handler.
2. Command = Help 4. Name = cmdhHelp
5. ReplyNormal.NumericCode = 200 6. ReplyNormal.Text = Help Follows
All of these steps you should be familiar with as they are similar to those implemented in QUIT. The additional property that is used for implementing the textual form of the response is the Response property which is a string list. If Response contains text, it will be sent to the client after ReplyNormal is sent. For implementation of the HELP command use the string list property editor for the Response property and enter:
Indy in Depth 121
(C) 2003 Atozed Computer Software Ltd.
This book is registered to Constantinos Pitsakis
Help - Display a list of supported commands and basic help on each.
DateTime <format> - Return the current date and/or time using the specified format.
If no format is specified the format yyyy-mm-dd hh:nn:ss will be used.
Quit - Terminate the session and disconnect.
Now if you connect to the server and send the HELP command the server will reply as follows:
200 Hello help
200 Help Follows
Help - Display a list of supported commands and basic help on each.
DateTime <format> - Return the current date and/or time using the specified format.
If no format is specified the format yyyy-mm-dd hh:nn:ss will be used.
Quit - Terminate the session and disconnect.
.
17.4.8 Implementing DATETIME
DATETIME is the final command in the implementation of this protocol. It differs from either QUIT or HELP in that it requires some custom functionality that cannot be created merely by using properties.
In the implementation of DATETIME an event will be used to implement this custom behavior.
First build the base command handler using steps you are already familiar with:
1. Create a new command handler.
2. Command = DateTime 3. Name = cmdhDateTime
4. ReplyNormal.NumericCode = 200
This time a ReplyNormal.Text was not defined, the event will custom defined it for each request. To define the event, use the Object Inspector while the DATETIME command handler is selected.
Switch to the events tab and create an OnCommand event. Delphi will create a event shell as shown next:
procedure TForm1.IdTCPServer1TIdCommandHandler2Command(ASender: TIdCommand);
begin end;
OnCommand passes in an argument of ASender which is of type TIdCommand. This is not the command handler, but the command itself. Command Handlers are global to all connections, while commands are specific to the connection being handled by this instance of the
OnCommand event. This ensures that the event can provide specific behavior to each client connection.
Before the event is called, Indy will create an instance of the command and initialize its properties based on the command handler. You can then use the command to change properties from their defaults, call methods to instruct the command to perform tasks, or access its Connection property to interact with the connection directly.
This protocol defines DATETIME as accepting an optional parameter specifying the format of the date and time to be returned. The command has support for this as well in the Params property, which is a string list. When a command is received from the client, if the command handler's
ParseParams property is True (True is the default) Indy will use the CmdDelimeter property (which defaults to #32 or space) to parse the command into the command and its parameters.
Servers 122
For example in this protocol the client may send:
DATETIME hhnnss
In this case, ASender.Params would contain the string "hhnnss" in ASender.Params[0]. The number of parameters can be determined by reading ASender.Params.Count.
Using these properties the OnCommand can be implemented as follows:
procedure TForm1.IdTCPServer1TIdCommandHandler2Command(ASender: TIdCommand);
var
LFormat: string;
begin
if ASender.Params.Count = 0 then begin LFormat := 'yyyy-mm-dd hh:nn:ss';
end else begin
LFormat := ASender.Params[0];
end;
ASender.Reply.Text.Text := FormatDateTime(LFormat, Now);
end;
This implementation merely reads the parameters and uses ASender.Reply.Text to send the reply back to the client. It is not needed to set ASender.Reply.NumericCode as Indy initializes it to 200 from the command handler's ReplyNormal.NumericCode.
Note the use of ASender.Reply.Text.Text. Text is required twice because the Text property of the command is a string list, and we are accessing TStrings.Text in addition to that. Since it is a string list, other methods or properties such as Add, Delete, etc may also be used. Text is used here as
ASender.Reply.Text may be pre-initialized in some cases and using ASender.Reply.Text.Text will overwrite any preexisting text.
If the demo is tested again using telnet, it will yield results similar to the following:
200 Hello datetime
200 2002-08-26 18:48:06
In some cases Params cannot be used. DATETIME is one of them. Consider if the user sends this as a command:
DATETIME mm dd yy
In this case Params.Count would be 3, and the event would fail and return only the value for months (mm). For cases where the parameter has embedded delimiters the UnparsedParams property of the command should be used instead. Optionally the ParseParams property can be set to False.
UnparsedParams will contain the data irregardless of the value of ParseParams, but setting it to false will increase efficiency by telling Indy that there is no need to parse the parameters into the Params property.
The event with the code modified to use UnparsedParams follows:
procedure TForm1.IdTCPServer1TIdCommandHandler2Command(ASender: TIdCommand);
var
LFormat: string;
begin
if ASender.Params.Count = 0 then begin LFormat := 'yyyy-mm-dd hh:nn:ss';
end else begin
LFormat := ASender.UnparsedParams;
end;
ASender.Reply.Text.Text := FormatDateTime(LFormat, Now);
end;
Indy in Depth 123
(C) 2003 Atozed Computer Software Ltd.