TIdCommandHandler:如何构造命令?

TIdCommandHandler: How to construct commands?

我正在使用 Delphi XE7。我以前从未使用过 Indy 组件。

我从 Embarcadero 找到了一个非常好的教程,叫做 Developing TCP/IP-based Server Applications using Indy Components。它显示了一个使用 TidCmdTCPServer 和命令处理程序的非常好的示例。

我的问题是我不明白如何构造命令。我在帮助文件和 Indy 主页中都找不到它。

查看下面的代码:

procedure TMyServer.InitializeCommandHandlers;
var
    NewCmd: TIdCommandHandler;
begin
    NewCmd                            := FCommandHandlers.Add;
    NewCmd.Command                    := 'HEARTBEAT'; { Do not Localize }
    NewCmd.OnCommand                  := CommandHEARTBEAT;
    NewCmd.ExceptionReply.NumericCode := 550;
    NewCmd.Description.Text           := 'Syntax: HEARTBEAT'; { do not localize }
    NewCmd.Disconnect                 := False;

    NewCmd                            := FCommandHandlers.Add;
    NewCmd.Command                    := 'COLOR'; { Do not Localize }
    NewCmd.CmdDelimiter               := #;
    NewCmd.ParamDelimiter             := '|';
    NewCmd.OnCommand                  := CommandCOLOR;
    NewCmd.ExceptionReply.NumericCode := 550;
    NewCmd.Description.Text           := 'Syntax: COLOR <sp> "GET | [SET" | color-"blue | red | yellow]"'; { do not localize }
    NewCmd.Disconnect                 := False;
end;

第一个命令 HEARTBEAT 相当简单,但 COLOR 命令则不然。

我没看懂这行:

NewCmd.Description.Text           := 'Syntax: COLOR <sp> "GET | [SET" | color-"blue | red | yellow]"'; { do not localize }

谁能解释一下它是如何构造的?或者给我一份我可以学习这个的文档?

"do not localize" 是什么意思?

语法 应该 是使用增强巴科斯范式 (BNF) 编写的,类似于 RFC 822, Section 2 - NOTATIONAL CONVENTIONS 中定义的语法。

COLOR 显然是命令名称。

<sp> 是一个 space 字符。

引号表示按原样显示的文字字符串。

在这种情况下,| 被用作传输数据中参数之间的分隔符,因此应该用引号引起来。

[] 在这种情况下用于将逻辑项组合在一起。但是,括号出现在引号内,这是错误的,因为它们实际上并未出现在传输中。

color- 是这种情况实际上也没有传输,也不应该出现在语法中。

因此,根据文章中提供的实际代码,服务器将接受以下命令(不区分大小写):

HEARTBEAT
COLOR GET
COLOR SET|BLUE
COLOR SET|RED
COLOR SET|YELLOW 

你可以在文章的客户端代码中清楚地看到:

IdTCPClient1.Socket.WriteLn('HEARTBEAT');
IdTCPClient1.IOHandler.WriteLn('COLOR GET');
case RadioGroup1.ItemIndex of
  0: IdTCPClient1.IOHandler.WriteLn('COLOR SET|BLUE');
  1: IdTCPClient1.IOHandler.WriteLn('COLOR SET|RED');
  2: IdTCPClient1.IOHandler.WriteLn('COLOR SET|YELLOW');
end;

正确的语法应该定义如下:

NewCmd.Description.Text := 'Syntax: COLOR <sp> ("GET" / ("SET" "|" ("BLUE" / "RED" / "YELLOW")))'; { do not localize }

{ do not localize } 是对自动国际化工具和翻译器的提示,该行包含需要保留原样且不本地化为任何特定语言的字符串文字。

话虽这么说,文章也提到了这一点:

Since we have chosen to use TidCmdTCPServer we cannot simply put one on a form. We must instead descend our own class base on TidCmdTCPServer and add all of our custom behavior to it. This was even the prefered way to go even when TidTCPServer supported command handlers.

这根本不是真的。 TIdCmdTCPServer.CommandHandlers 集合(Indy 9 中的 TIdTCPServer.CommandHandlers)在设计时可用,并且可以使用对象检查器及其内置集合编辑器进行完全编辑,包括分配每个命令的事件处理程序。这是使用它的首选方式,而且一直都是。派生自定义组件的唯一原因是如果您需要模块化命令处理代码以使其可重用(Indy 有几个 TIdCmdTCPServer 自己的派生组件)。否则,派生和安装新组件就太过分了。