Delphi 如何使用TIdTelnet抑制回声?

Delphi 如何使用TIdTelnet抑制回声?,delphi,telnet,indy10,Delphi,Telnet,Indy10,使用Indy10-DelphiXE。 我如何告诉我使用TIdTelnet连接的telnet服务器不要回显我向telnet服务器发送的命令 这是我目前的尝试(不起作用),我尝试在每次telnet写入时发送序列IAC DO SUPPRESS_LOCAL_ECHO,但我相信这必须在协商阶段完成 uses TIdTelnet, ... procedure TIOTelnetConnection.SendSupressEcho; var Resp: TIdBytes; begin SetL

使用Indy10-DelphiXE。 我如何告诉我使用
TIdTelnet
连接的telnet服务器不要回显我向telnet服务器发送的命令

这是我目前的尝试(不起作用),我尝试在每次telnet写入时发送序列IAC DO SUPPRESS_LOCAL_ECHO,但我相信这必须在协商阶段完成

uses
  TIdTelnet,

...
procedure TIOTelnetConnection.SendSupressEcho;

var
  Resp: TIdBytes;

begin
 SetLength(Resp, 3);
 Resp[0] := TNC_IAC;
 Resp[1] := TNC_DO;
 Resp[2] := TNO_SUPLOCALECHO;
 FIOConnection.IOHandler.Write(Resp);
end;

procedure TIOTelnetConnection.Write(Str: AnsiString);
begin
 SendSupressEcho;
 if Str <> '' then
  FIOConnection.IOHandler.Write(Str);
end;
使用
TIdTelnet,
...
程序TIOTelnetConnection.SENDUPRSSECHO;
变量
Resp:TIdBytes;
开始
设定长度(分别为3);
Resp[0]:=TNC_IAC;
Resp[1]:=TNC_DO;
Resp[2]:=TNO_SUPLOCALECHO;
FIOConnection.IOHandler.Write(Resp);
结束;
过程TIOTelnetConnection.Write(Str:AnsiString);
开始
Sendsessecho;
如果Str“”那么
FIOConnection.IOHandler.Write(Str);
结束;

查看
TIdTelnet
源代码,我看到了
协商
过程,但它是受保护的,我如何覆盖它的行为?

如果服务器向您发送
IAC WILL ECHO
TIdTelnet
硬编码以发送
IAC DO ECHO
响应,然后触发
OnTelnetCommand(tncnolicalecho)
事件,告诉您不要在本地回显您发送的内容


如果服务器向您发送
IAC WONT ECHO
TIdTelnet
将被硬编码为发送
IAC DONT ECHO
响应,然后触发
OnTelnetCommand(tncLocalEcho)
事件,告诉您本地回显您发送的内容


如果服务器向您发送
IAC DO ECHO
TIdTelnet
被硬编码为发送
IAC将ECHO
响应,然后触发
OnTelnetCommand(tncEcho)
事件,告诉您回显收到的任何内容


如果服务器向您发送
IAC DONT ECHO
TIdTelnet
被硬编码为发送
IAC WONT ECHO
响应,然后触发
OnTelnetCommand(tncLocalEcho)
事件,告诉您回显收到的任何内容


因此,如果您不希望服务器回显给您,您可以向服务器发送一个
IAC DONT echo
命令,而不是
IAC DO SUPLOCALECHO
命令。然后服务器将相应地使用
IAC WONT echo
IAC will echo
进行回复(显然,
TIdTelnet
会回复,但服务器不会再次回复,因为它的
ECHO
当前状态不会改变,从而避免了无休止的响应循环)。

@Remy Lebeau:据我所知,你是说: 如果服务器向您发送IAC DO回显,则TIdTelnet将硬编码为发送IAC WILL回显响应,然后触发OnTelnetCommand(tncEcho)事件,告诉您回显收到的任何内容

这是有道理的,并且与RFC857的目标一致

但是,在我们的代码中:

procedure TIdTelnet.Negotiate;
...
      TNC_DONT:
        begin
          b := IOHandler.ReadByte;
          case b of
            TNO_ECHO:
              begin
                DoTelnetCommand(tncEcho);
                //DoStatus('ECHO');    {Do not Localize}
                Reply := TNC_WONT;
              end;
            else
              Reply := TNC_WONT;
          end;

该代码肯定不正确?(在Indy的10.6.0.497版中)

我相信这会更有意义:

 procedure TIdTelnet.Negotiate;
 ...
      TNC_DONT:
         begin
           b := IOHandler.ReadByte;
           case b of
             TNO_ECHO:
               begin
               // Agree not to echo back everything received from server 
               // (This being the default - you shouldn't echo unless asked to)
                  Reply := TNC_WONT;            
               // Therefore only print locally what is sent to server
               // (Again: this is the default behavior without negotiation) 
                  DoTelnetCommand(tncLocalEcho);
               end;
             else
               Reply := TNC_WONT;
           end;

换言之,我相信代码现在已经从它应该是的东西中被交换了,也就是说发送DO ECHO的服务器应该生成tncEcho令牌,这就是您在上面的引用中所说的

这个bug是如何存活这么长时间的?(可能是因为大多数Telnet服务器不再为RFC857回声协商而烦恼了)


不幸的是,目前我看到的唯一“补偿”此错误的方法是创建IDTelnet.pas文件的副本;在项目经理中将其链接到您的项目;然后对该副本进行如上所述的更正。

来解决最初的问题:“如何使用TIdTelnet抑制echo?”,我建议采取以下步骤:

  • 将TIdConnectionIntercept添加到表单并将其挂接到 通过使用对象的Intercept属性创建TIdTelnet组件 检查员

  • 为TIdConnectionIntercept OnSend生成事件处理程序 事件

  • 使用此选项可检测其var ABuffer:TIdBytes参数何时获取 对服务器关于回送的协商命令的响应。 请注意,缓冲区将精确且仅包含 由于响应的填充和发送方式 TIdTelnet.协商

  • 根据需要更改中间字节(即强制执行从WILL到WONT或DO到Don的更改,以适应您试图强制执行的内容)

  • 约伯是个“好联合国”


    当然,请记住,此技术会在调用TidTelnet OnTelnetCommand后注入更改,因此您必须更改在该处理程序中设置的任何内容,以适应修改后的响应。

    谢谢,我发现这有点让人困惑,但事实上IAC DONT ECHO正是我要寻找的序列。有没有可能在稍后将其更改为属性Indy?
    TIdTelnet
    的修订非常简单,因此我确信在未来的版本中可以做很多事情来改进它。不幸的是,我发现在客户端强制执行DONT将导致用Delphi XE4编写的服务器在IOHandler中引发断言异常!这似乎是因为硬编码n TidTelnet生成一个额外的响应:即我们得到序列WILL->DONT->WONT->DONT(最后一个DONT不应该发生)。意外的3字节命令可能会导致服务器(在启用Unicode支持的情况下编写)检测到“缺少的字节”并引发断言异常。总结一下:(a)TidTelnet将在will-DONT-WONT序列中频繁应答一次,并且(b)TidTelnetServer可能存在与接收意外奇数字节序列相关的错误。这可能是因为我必须使用result:=AContext.Connection.IoHandler.WaitFor(chr(TNC_IAC),False,False,Indy8BitEncoding,Timeout);在服务器代码中,因为“WaitFor”没有TidByte重载。这种重载的省略可能是问题的核心-尽管我仍然认为意外传入的数据使服务器崩溃并导致其光盘损坏不是很好
     procedure TIdTelnet.Negotiate;
     ...
          TNC_DONT:
             begin
               b := IOHandler.ReadByte;
               case b of
                 TNO_ECHO:
                   begin
                   // Agree not to echo back everything received from server 
                   // (This being the default - you shouldn't echo unless asked to)
                      Reply := TNC_WONT;            
                   // Therefore only print locally what is sent to server
                   // (Again: this is the default behavior without negotiation) 
                      DoTelnetCommand(tncLocalEcho);
                   end;
                 else
                   Reply := TNC_WONT;
               end;
    
       TNC_DO:
         begin
           b := IOHandler.ReadByte;
           case b of
             TNO_ECHO:
               begin
               // Agree to echo back everything received from server 
                  Reply := TNC_WILL;
                  DoTelnetCommand(tncEcho); 
               // Therefore you may still have to locally print what you send
               // (i.e. local echo is usually still implicit in this)
               end;